diff options
54 files changed, 1124 insertions, 656 deletions
diff --git a/arch/arm/mach-vexpress/Kconfig b/arch/arm/mach-vexpress/Kconfig index 365795447804..c77170c04fd0 100644 --- a/arch/arm/mach-vexpress/Kconfig +++ b/arch/arm/mach-vexpress/Kconfig | |||
| @@ -66,10 +66,22 @@ config ARCH_VEXPRESS_DCSCB | |||
| 66 | This is needed to provide CPU and cluster power management | 66 | This is needed to provide CPU and cluster power management |
| 67 | on RTSM implementing big.LITTLE. | 67 | on RTSM implementing big.LITTLE. |
| 68 | 68 | ||
| 69 | config ARCH_VEXPRESS_SPC | ||
| 70 | bool "Versatile Express Serial Power Controller (SPC)" | ||
| 71 | select ARCH_HAS_CPUFREQ | ||
| 72 | select ARCH_HAS_OPP | ||
| 73 | select PM_OPP | ||
| 74 | help | ||
| 75 | The TC2 (A15x2 A7x3) versatile express core tile integrates a logic | ||
| 76 | block called Serial Power Controller (SPC) that provides the interface | ||
| 77 | between the dual cluster test-chip and the M3 microcontroller that | ||
| 78 | carries out power management. | ||
| 79 | |||
| 69 | config ARCH_VEXPRESS_TC2_PM | 80 | config ARCH_VEXPRESS_TC2_PM |
| 70 | bool "Versatile Express TC2 power management" | 81 | bool "Versatile Express TC2 power management" |
| 71 | depends on MCPM | 82 | depends on MCPM |
| 72 | select ARM_CCI | 83 | select ARM_CCI |
| 84 | select ARCH_VEXPRESS_SPC | ||
| 73 | help | 85 | help |
| 74 | Support for CPU and cluster power management on Versatile Express | 86 | Support for CPU and cluster power management on Versatile Express |
| 75 | with a TC2 (A15x2 A7x3) big.LITTLE core tile. | 87 | with a TC2 (A15x2 A7x3) big.LITTLE core tile. |
diff --git a/arch/arm/mach-vexpress/Makefile b/arch/arm/mach-vexpress/Makefile index 505e64ab3eae..0997e0b7494c 100644 --- a/arch/arm/mach-vexpress/Makefile +++ b/arch/arm/mach-vexpress/Makefile | |||
| @@ -8,7 +8,8 @@ obj-y := v2m.o | |||
| 8 | obj-$(CONFIG_ARCH_VEXPRESS_CA9X4) += ct-ca9x4.o | 8 | obj-$(CONFIG_ARCH_VEXPRESS_CA9X4) += ct-ca9x4.o |
| 9 | obj-$(CONFIG_ARCH_VEXPRESS_DCSCB) += dcscb.o dcscb_setup.o | 9 | obj-$(CONFIG_ARCH_VEXPRESS_DCSCB) += dcscb.o dcscb_setup.o |
| 10 | CFLAGS_dcscb.o += -march=armv7-a | 10 | CFLAGS_dcscb.o += -march=armv7-a |
| 11 | obj-$(CONFIG_ARCH_VEXPRESS_TC2_PM) += tc2_pm.o spc.o | 11 | obj-$(CONFIG_ARCH_VEXPRESS_SPC) += spc.o |
| 12 | obj-$(CONFIG_ARCH_VEXPRESS_TC2_PM) += tc2_pm.o | ||
| 12 | CFLAGS_tc2_pm.o += -march=armv7-a | 13 | CFLAGS_tc2_pm.o += -march=armv7-a |
| 13 | obj-$(CONFIG_SMP) += platsmp.o | 14 | obj-$(CONFIG_SMP) += platsmp.o |
| 14 | obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o | 15 | obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o |
diff --git a/arch/arm/mach-vexpress/spc.c b/arch/arm/mach-vexpress/spc.c index eefb029197ca..033d34dcbd3f 100644 --- a/arch/arm/mach-vexpress/spc.c +++ b/arch/arm/mach-vexpress/spc.c | |||
| @@ -17,14 +17,31 @@ | |||
| 17 | * GNU General Public License for more details. | 17 | * GNU General Public License for more details. |
| 18 | */ | 18 | */ |
| 19 | 19 | ||
| 20 | #include <linux/clk-provider.h> | ||
| 21 | #include <linux/clkdev.h> | ||
| 22 | #include <linux/cpu.h> | ||
| 23 | #include <linux/delay.h> | ||
| 20 | #include <linux/err.h> | 24 | #include <linux/err.h> |
| 25 | #include <linux/interrupt.h> | ||
| 21 | #include <linux/io.h> | 26 | #include <linux/io.h> |
| 27 | #include <linux/platform_device.h> | ||
| 28 | #include <linux/pm_opp.h> | ||
| 22 | #include <linux/slab.h> | 29 | #include <linux/slab.h> |
| 30 | #include <linux/semaphore.h> | ||
| 23 | 31 | ||
| 24 | #include <asm/cacheflush.h> | 32 | #include <asm/cacheflush.h> |
| 25 | 33 | ||
| 26 | #define SPCLOG "vexpress-spc: " | 34 | #define SPCLOG "vexpress-spc: " |
| 27 | 35 | ||
| 36 | #define PERF_LVL_A15 0x00 | ||
| 37 | #define PERF_REQ_A15 0x04 | ||
| 38 | #define PERF_LVL_A7 0x08 | ||
| 39 | #define PERF_REQ_A7 0x0c | ||
| 40 | #define COMMS 0x10 | ||
| 41 | #define COMMS_REQ 0x14 | ||
| 42 | #define PWC_STATUS 0x18 | ||
| 43 | #define PWC_FLAG 0x1c | ||
| 44 | |||
| 28 | /* SPC wake-up IRQs status and mask */ | 45 | /* SPC wake-up IRQs status and mask */ |
| 29 | #define WAKE_INT_MASK 0x24 | 46 | #define WAKE_INT_MASK 0x24 |
| 30 | #define WAKE_INT_RAW 0x28 | 47 | #define WAKE_INT_RAW 0x28 |
| @@ -36,12 +53,45 @@ | |||
| 36 | #define A15_BX_ADDR0 0x68 | 53 | #define A15_BX_ADDR0 0x68 |
| 37 | #define A7_BX_ADDR0 0x78 | 54 | #define A7_BX_ADDR0 0x78 |
| 38 | 55 | ||
| 56 | /* SPC system config interface registers */ | ||
| 57 | #define SYSCFG_WDATA 0x70 | ||
| 58 | #define SYSCFG_RDATA 0x74 | ||
| 59 | |||
| 60 | /* A15/A7 OPP virtual register base */ | ||
| 61 | #define A15_PERFVAL_BASE 0xC10 | ||
| 62 | #define A7_PERFVAL_BASE 0xC30 | ||
| 63 | |||
| 64 | /* Config interface control bits */ | ||
| 65 | #define SYSCFG_START (1 << 31) | ||
| 66 | #define SYSCFG_SCC (6 << 20) | ||
| 67 | #define SYSCFG_STAT (14 << 20) | ||
| 68 | |||
| 39 | /* wake-up interrupt masks */ | 69 | /* wake-up interrupt masks */ |
| 40 | #define GBL_WAKEUP_INT_MSK (0x3 << 10) | 70 | #define GBL_WAKEUP_INT_MSK (0x3 << 10) |
| 41 | 71 | ||
| 42 | /* TC2 static dual-cluster configuration */ | 72 | /* TC2 static dual-cluster configuration */ |
| 43 | #define MAX_CLUSTERS 2 | 73 | #define MAX_CLUSTERS 2 |
| 44 | 74 | ||
| 75 | /* | ||
| 76 | * Even though the SPC takes max 3-5 ms to complete any OPP/COMMS | ||
| 77 | * operation, the operation could start just before jiffie is about | ||
| 78 | * to be incremented. So setting timeout value of 20ms = 2jiffies@100Hz | ||
| 79 | */ | ||
| 80 | #define TIMEOUT_US 20000 | ||
| 81 | |||
| 82 | #define MAX_OPPS 8 | ||
| 83 | #define CA15_DVFS 0 | ||
| 84 | #define CA7_DVFS 1 | ||
| 85 | #define SPC_SYS_CFG 2 | ||
| 86 | #define STAT_COMPLETE(type) ((1 << 0) << (type << 2)) | ||
| 87 | #define STAT_ERR(type) ((1 << 1) << (type << 2)) | ||
| 88 | #define RESPONSE_MASK(type) (STAT_COMPLETE(type) | STAT_ERR(type)) | ||
| 89 | |||
| 90 | struct ve_spc_opp { | ||
| 91 | unsigned long freq; | ||
| 92 | unsigned long u_volt; | ||
| 93 | }; | ||
| 94 | |||
| 45 | struct ve_spc_drvdata { | 95 | struct ve_spc_drvdata { |
| 46 | void __iomem *baseaddr; | 96 | void __iomem *baseaddr; |
| 47 | /* | 97 | /* |
| @@ -49,6 +99,12 @@ struct ve_spc_drvdata { | |||
| 49 | * It corresponds to A15 processors MPIDR[15:8] bitfield | 99 | * It corresponds to A15 processors MPIDR[15:8] bitfield |
| 50 | */ | 100 | */ |
| 51 | u32 a15_clusid; | 101 | u32 a15_clusid; |
| 102 | uint32_t cur_rsp_mask; | ||
| 103 | uint32_t cur_rsp_stat; | ||
| 104 | struct semaphore sem; | ||
| 105 | struct completion done; | ||
| 106 | struct ve_spc_opp *opps[MAX_CLUSTERS]; | ||
| 107 | int num_opps[MAX_CLUSTERS]; | ||
| 52 | }; | 108 | }; |
| 53 | 109 | ||
| 54 | static struct ve_spc_drvdata *info; | 110 | static struct ve_spc_drvdata *info; |
| @@ -157,8 +213,197 @@ void ve_spc_powerdown(u32 cluster, bool enable) | |||
| 157 | writel_relaxed(enable, info->baseaddr + pwdrn_reg); | 213 | writel_relaxed(enable, info->baseaddr + pwdrn_reg); |
| 158 | } | 214 | } |
| 159 | 215 | ||
| 160 | int __init ve_spc_init(void __iomem *baseaddr, u32 a15_clusid) | 216 | static int ve_spc_get_performance(int cluster, u32 *freq) |
| 217 | { | ||
| 218 | struct ve_spc_opp *opps = info->opps[cluster]; | ||
| 219 | u32 perf_cfg_reg = 0; | ||
| 220 | u32 perf; | ||
| 221 | |||
| 222 | perf_cfg_reg = cluster_is_a15(cluster) ? PERF_LVL_A15 : PERF_LVL_A7; | ||
| 223 | |||
| 224 | perf = readl_relaxed(info->baseaddr + perf_cfg_reg); | ||
| 225 | if (perf >= info->num_opps[cluster]) | ||
| 226 | return -EINVAL; | ||
| 227 | |||
| 228 | opps += perf; | ||
| 229 | *freq = opps->freq; | ||
| 230 | |||
| 231 | return 0; | ||
| 232 | } | ||
| 233 | |||
| 234 | /* find closest match to given frequency in OPP table */ | ||
| 235 | static int ve_spc_round_performance(int cluster, u32 freq) | ||
| 236 | { | ||
| 237 | int idx, max_opp = info->num_opps[cluster]; | ||
| 238 | struct ve_spc_opp *opps = info->opps[cluster]; | ||
| 239 | u32 fmin = 0, fmax = ~0, ftmp; | ||
| 240 | |||
| 241 | freq /= 1000; /* OPP entries in kHz */ | ||
| 242 | for (idx = 0; idx < max_opp; idx++, opps++) { | ||
| 243 | ftmp = opps->freq; | ||
| 244 | if (ftmp >= freq) { | ||
| 245 | if (ftmp <= fmax) | ||
| 246 | fmax = ftmp; | ||
| 247 | } else { | ||
| 248 | if (ftmp >= fmin) | ||
| 249 | fmin = ftmp; | ||
| 250 | } | ||
| 251 | } | ||
| 252 | if (fmax != ~0) | ||
| 253 | return fmax * 1000; | ||
| 254 | else | ||
| 255 | return fmin * 1000; | ||
| 256 | } | ||
| 257 | |||
| 258 | static int ve_spc_find_performance_index(int cluster, u32 freq) | ||
| 259 | { | ||
| 260 | int idx, max_opp = info->num_opps[cluster]; | ||
| 261 | struct ve_spc_opp *opps = info->opps[cluster]; | ||
| 262 | |||
| 263 | for (idx = 0; idx < max_opp; idx++, opps++) | ||
| 264 | if (opps->freq == freq) | ||
| 265 | break; | ||
| 266 | return (idx == max_opp) ? -EINVAL : idx; | ||
| 267 | } | ||
| 268 | |||
| 269 | static int ve_spc_waitforcompletion(int req_type) | ||
| 270 | { | ||
| 271 | int ret = wait_for_completion_interruptible_timeout( | ||
| 272 | &info->done, usecs_to_jiffies(TIMEOUT_US)); | ||
| 273 | if (ret == 0) | ||
| 274 | ret = -ETIMEDOUT; | ||
| 275 | else if (ret > 0) | ||
| 276 | ret = info->cur_rsp_stat & STAT_COMPLETE(req_type) ? 0 : -EIO; | ||
| 277 | return ret; | ||
| 278 | } | ||
| 279 | |||
| 280 | static int ve_spc_set_performance(int cluster, u32 freq) | ||
| 281 | { | ||
| 282 | u32 perf_cfg_reg, perf_stat_reg; | ||
| 283 | int ret, perf, req_type; | ||
| 284 | |||
| 285 | if (cluster_is_a15(cluster)) { | ||
| 286 | req_type = CA15_DVFS; | ||
| 287 | perf_cfg_reg = PERF_LVL_A15; | ||
| 288 | perf_stat_reg = PERF_REQ_A15; | ||
| 289 | } else { | ||
| 290 | req_type = CA7_DVFS; | ||
| 291 | perf_cfg_reg = PERF_LVL_A7; | ||
| 292 | perf_stat_reg = PERF_REQ_A7; | ||
| 293 | } | ||
| 294 | |||
| 295 | perf = ve_spc_find_performance_index(cluster, freq); | ||
| 296 | |||
| 297 | if (perf < 0) | ||
| 298 | return perf; | ||
| 299 | |||
| 300 | if (down_timeout(&info->sem, usecs_to_jiffies(TIMEOUT_US))) | ||
| 301 | return -ETIME; | ||
| 302 | |||
| 303 | init_completion(&info->done); | ||
| 304 | info->cur_rsp_mask = RESPONSE_MASK(req_type); | ||
| 305 | |||
| 306 | writel(perf, info->baseaddr + perf_cfg_reg); | ||
| 307 | ret = ve_spc_waitforcompletion(req_type); | ||
| 308 | |||
| 309 | info->cur_rsp_mask = 0; | ||
| 310 | up(&info->sem); | ||
| 311 | |||
| 312 | return ret; | ||
| 313 | } | ||
| 314 | |||
| 315 | static int ve_spc_read_sys_cfg(int func, int offset, uint32_t *data) | ||
| 316 | { | ||
| 317 | int ret; | ||
| 318 | |||
| 319 | if (down_timeout(&info->sem, usecs_to_jiffies(TIMEOUT_US))) | ||
| 320 | return -ETIME; | ||
| 321 | |||
| 322 | init_completion(&info->done); | ||
| 323 | info->cur_rsp_mask = RESPONSE_MASK(SPC_SYS_CFG); | ||
| 324 | |||
| 325 | /* Set the control value */ | ||
| 326 | writel(SYSCFG_START | func | offset >> 2, info->baseaddr + COMMS); | ||
| 327 | ret = ve_spc_waitforcompletion(SPC_SYS_CFG); | ||
| 328 | |||
| 329 | if (ret == 0) | ||
| 330 | *data = readl(info->baseaddr + SYSCFG_RDATA); | ||
| 331 | |||
| 332 | info->cur_rsp_mask = 0; | ||
| 333 | up(&info->sem); | ||
| 334 | |||
| 335 | return ret; | ||
| 336 | } | ||
| 337 | |||
| 338 | static irqreturn_t ve_spc_irq_handler(int irq, void *data) | ||
| 339 | { | ||
| 340 | struct ve_spc_drvdata *drv_data = data; | ||
| 341 | uint32_t status = readl_relaxed(drv_data->baseaddr + PWC_STATUS); | ||
| 342 | |||
| 343 | if (info->cur_rsp_mask & status) { | ||
| 344 | info->cur_rsp_stat = status; | ||
| 345 | complete(&drv_data->done); | ||
| 346 | } | ||
| 347 | |||
| 348 | return IRQ_HANDLED; | ||
| 349 | } | ||
| 350 | |||
| 351 | /* | ||
| 352 | * +--------------------------+ | ||
| 353 | * | 31 20 | 19 0 | | ||
| 354 | * +--------------------------+ | ||
| 355 | * | u_volt | freq(kHz) | | ||
| 356 | * +--------------------------+ | ||
| 357 | */ | ||
| 358 | #define MULT_FACTOR 20 | ||
| 359 | #define VOLT_SHIFT 20 | ||
| 360 | #define FREQ_MASK (0xFFFFF) | ||
| 361 | static int ve_spc_populate_opps(uint32_t cluster) | ||
| 161 | { | 362 | { |
| 363 | uint32_t data = 0, off, ret, idx; | ||
| 364 | struct ve_spc_opp *opps; | ||
| 365 | |||
| 366 | opps = kzalloc(sizeof(*opps) * MAX_OPPS, GFP_KERNEL); | ||
| 367 | if (!opps) | ||
| 368 | return -ENOMEM; | ||
| 369 | |||
| 370 | info->opps[cluster] = opps; | ||
| 371 | |||
| 372 | off = cluster_is_a15(cluster) ? A15_PERFVAL_BASE : A7_PERFVAL_BASE; | ||
| 373 | for (idx = 0; idx < MAX_OPPS; idx++, off += 4, opps++) { | ||
| 374 | ret = ve_spc_read_sys_cfg(SYSCFG_SCC, off, &data); | ||
| 375 | if (!ret) { | ||
| 376 | opps->freq = (data & FREQ_MASK) * MULT_FACTOR; | ||
| 377 | opps->u_volt = data >> VOLT_SHIFT; | ||
| 378 | } else { | ||
| 379 | break; | ||
| 380 | } | ||
| 381 | } | ||
| 382 | info->num_opps[cluster] = idx; | ||
| 383 | |||
| 384 | return ret; | ||
| 385 | } | ||
| 386 | |||
| 387 | static int ve_init_opp_table(struct device *cpu_dev) | ||
| 388 | { | ||
| 389 | int cluster = topology_physical_package_id(cpu_dev->id); | ||
| 390 | int idx, ret = 0, max_opp = info->num_opps[cluster]; | ||
| 391 | struct ve_spc_opp *opps = info->opps[cluster]; | ||
| 392 | |||
| 393 | for (idx = 0; idx < max_opp; idx++, opps++) { | ||
| 394 | ret = dev_pm_opp_add(cpu_dev, opps->freq * 1000, opps->u_volt); | ||
| 395 | if (ret) { | ||
| 396 | dev_warn(cpu_dev, "failed to add opp %lu %lu\n", | ||
| 397 | opps->freq, opps->u_volt); | ||
| 398 | return ret; | ||
| 399 | } | ||
| 400 | } | ||
| 401 | return ret; | ||
| 402 | } | ||
| 403 | |||
| 404 | int __init ve_spc_init(void __iomem *baseaddr, u32 a15_clusid, int irq) | ||
| 405 | { | ||
| 406 | int ret; | ||
| 162 | info = kzalloc(sizeof(*info), GFP_KERNEL); | 407 | info = kzalloc(sizeof(*info), GFP_KERNEL); |
| 163 | if (!info) { | 408 | if (!info) { |
| 164 | pr_err(SPCLOG "unable to allocate mem\n"); | 409 | pr_err(SPCLOG "unable to allocate mem\n"); |
| @@ -168,6 +413,25 @@ int __init ve_spc_init(void __iomem *baseaddr, u32 a15_clusid) | |||
| 168 | info->baseaddr = baseaddr; | 413 | info->baseaddr = baseaddr; |
| 169 | info->a15_clusid = a15_clusid; | 414 | info->a15_clusid = a15_clusid; |
| 170 | 415 | ||
| 416 | if (irq <= 0) { | ||
| 417 | pr_err(SPCLOG "Invalid IRQ %d\n", irq); | ||
| 418 | kfree(info); | ||
| 419 | return -EINVAL; | ||
| 420 | } | ||
| 421 | |||
| 422 | init_completion(&info->done); | ||
| 423 | |||
| 424 | readl_relaxed(info->baseaddr + PWC_STATUS); | ||
| 425 | |||
| 426 | ret = request_irq(irq, ve_spc_irq_handler, IRQF_TRIGGER_HIGH | ||
| 427 | | IRQF_ONESHOT, "vexpress-spc", info); | ||
| 428 | if (ret) { | ||
| 429 | pr_err(SPCLOG "IRQ %d request failed\n", irq); | ||
| 430 | kfree(info); | ||
| 431 | return -ENODEV; | ||
| 432 | } | ||
| 433 | |||
| 434 | sema_init(&info->sem, 1); | ||
| 171 | /* | 435 | /* |
| 172 | * Multi-cluster systems may need this data when non-coherent, during | 436 | * Multi-cluster systems may need this data when non-coherent, during |
| 173 | * cluster power-up/power-down. Make sure driver info reaches main | 437 | * cluster power-up/power-down. Make sure driver info reaches main |
| @@ -178,3 +442,103 @@ int __init ve_spc_init(void __iomem *baseaddr, u32 a15_clusid) | |||
| 178 | 442 | ||
| 179 | return 0; | 443 | return 0; |
| 180 | } | 444 | } |
| 445 | |||
| 446 | struct clk_spc { | ||
| 447 | struct clk_hw hw; | ||
| 448 | int cluster; | ||
| 449 | }; | ||
| 450 | |||
| 451 | #define to_clk_spc(spc) container_of(spc, struct clk_spc, hw) | ||
| 452 | static unsigned long spc_recalc_rate(struct clk_hw *hw, | ||
| 453 | unsigned long parent_rate) | ||
| 454 | { | ||
| 455 | struct clk_spc *spc = to_clk_spc(hw); | ||
| 456 | u32 freq; | ||
| 457 | |||
| 458 | if (ve_spc_get_performance(spc->cluster, &freq)) | ||
| 459 | return -EIO; | ||
| 460 | |||
| 461 | return freq * 1000; | ||
| 462 | } | ||
| 463 | |||
| 464 | static long spc_round_rate(struct clk_hw *hw, unsigned long drate, | ||
| 465 | unsigned long *parent_rate) | ||
| 466 | { | ||
| 467 | struct clk_spc *spc = to_clk_spc(hw); | ||
| 468 | |||
| 469 | return ve_spc_round_performance(spc->cluster, drate); | ||
| 470 | } | ||
| 471 | |||
| 472 | static int spc_set_rate(struct clk_hw *hw, unsigned long rate, | ||
| 473 | unsigned long parent_rate) | ||
| 474 | { | ||
| 475 | struct clk_spc *spc = to_clk_spc(hw); | ||
| 476 | |||
| 477 | return ve_spc_set_performance(spc->cluster, rate / 1000); | ||
| 478 | } | ||
| 479 | |||
| 480 | static struct clk_ops clk_spc_ops = { | ||
| 481 | .recalc_rate = spc_recalc_rate, | ||
| 482 | .round_rate = spc_round_rate, | ||
| 483 | .set_rate = spc_set_rate, | ||
| 484 | }; | ||
| 485 | |||
| 486 | static struct clk *ve_spc_clk_register(struct device *cpu_dev) | ||
| 487 | { | ||
| 488 | struct clk_init_data init; | ||
| 489 | struct clk_spc *spc; | ||
| 490 | |||
| 491 | spc = kzalloc(sizeof(*spc), GFP_KERNEL); | ||
| 492 | if (!spc) { | ||
| 493 | pr_err("could not allocate spc clk\n"); | ||
| 494 | return ERR_PTR(-ENOMEM); | ||
| 495 | } | ||
| 496 | |||
| 497 | spc->hw.init = &init; | ||
| 498 | spc->cluster = topology_physical_package_id(cpu_dev->id); | ||
| 499 | |||
| 500 | init.name = dev_name(cpu_dev); | ||
| 501 | init.ops = &clk_spc_ops; | ||
| 502 | init.flags = CLK_IS_ROOT | CLK_GET_RATE_NOCACHE; | ||
| 503 | init.num_parents = 0; | ||
| 504 | |||
| 505 | return devm_clk_register(cpu_dev, &spc->hw); | ||
| 506 | } | ||
| 507 | |||
| 508 | static int __init ve_spc_clk_init(void) | ||
| 509 | { | ||
| 510 | int cpu; | ||
| 511 | struct clk *clk; | ||
| 512 | |||
| 513 | if (!info) | ||
| 514 | return 0; /* Continue only if SPC is initialised */ | ||
| 515 | |||
| 516 | if (ve_spc_populate_opps(0) || ve_spc_populate_opps(1)) { | ||
| 517 | pr_err("failed to build OPP table\n"); | ||
| 518 | return -ENODEV; | ||
| 519 | } | ||
| 520 | |||
| 521 | for_each_possible_cpu(cpu) { | ||
| 522 | struct device *cpu_dev = get_cpu_device(cpu); | ||
| 523 | if (!cpu_dev) { | ||
| 524 | pr_warn("failed to get cpu%d device\n", cpu); | ||
| 525 | continue; | ||
| 526 | } | ||
| 527 | clk = ve_spc_clk_register(cpu_dev); | ||
| 528 | if (IS_ERR(clk)) { | ||
| 529 | pr_warn("failed to register cpu%d clock\n", cpu); | ||
| 530 | continue; | ||
| 531 | } | ||
| 532 | if (clk_register_clkdev(clk, NULL, dev_name(cpu_dev))) { | ||
| 533 | pr_warn("failed to register cpu%d clock lookup\n", cpu); | ||
| 534 | continue; | ||
| 535 | } | ||
| 536 | |||
| 537 | if (ve_init_opp_table(cpu_dev)) | ||
| 538 | pr_warn("failed to initialise cpu%d opp table\n", cpu); | ||
| 539 | } | ||
| 540 | |||
| 541 | platform_device_register_simple("vexpress-spc-cpufreq", -1, NULL, 0); | ||
| 542 | return 0; | ||
| 543 | } | ||
| 544 | module_init(ve_spc_clk_init); | ||
diff --git a/arch/arm/mach-vexpress/spc.h b/arch/arm/mach-vexpress/spc.h index 5f7e4a446a17..dbd44c3720f9 100644 --- a/arch/arm/mach-vexpress/spc.h +++ b/arch/arm/mach-vexpress/spc.h | |||
| @@ -15,7 +15,7 @@ | |||
| 15 | #ifndef __SPC_H_ | 15 | #ifndef __SPC_H_ |
| 16 | #define __SPC_H_ | 16 | #define __SPC_H_ |
| 17 | 17 | ||
| 18 | int __init ve_spc_init(void __iomem *base, u32 a15_clusid); | 18 | int __init ve_spc_init(void __iomem *base, u32 a15_clusid, int irq); |
| 19 | void ve_spc_global_wakeup_irq(bool set); | 19 | void ve_spc_global_wakeup_irq(bool set); |
| 20 | void ve_spc_cpu_wakeup_irq(u32 cluster, u32 cpu, bool set); | 20 | void ve_spc_cpu_wakeup_irq(u32 cluster, u32 cpu, bool set); |
| 21 | void ve_spc_set_resume_addr(u32 cluster, u32 cpu, u32 addr); | 21 | void ve_spc_set_resume_addr(u32 cluster, u32 cpu, u32 addr); |
diff --git a/arch/arm/mach-vexpress/tc2_pm.c b/arch/arm/mach-vexpress/tc2_pm.c index e6eb48192912..d38130aba464 100644 --- a/arch/arm/mach-vexpress/tc2_pm.c +++ b/arch/arm/mach-vexpress/tc2_pm.c | |||
| @@ -16,6 +16,7 @@ | |||
| 16 | #include <linux/io.h> | 16 | #include <linux/io.h> |
| 17 | #include <linux/kernel.h> | 17 | #include <linux/kernel.h> |
| 18 | #include <linux/of_address.h> | 18 | #include <linux/of_address.h> |
| 19 | #include <linux/of_irq.h> | ||
| 19 | #include <linux/spinlock.h> | 20 | #include <linux/spinlock.h> |
| 20 | #include <linux/errno.h> | 21 | #include <linux/errno.h> |
| 21 | #include <linux/irqchip/arm-gic.h> | 22 | #include <linux/irqchip/arm-gic.h> |
| @@ -311,7 +312,7 @@ static void __naked tc2_pm_power_up_setup(unsigned int affinity_level) | |||
| 311 | 312 | ||
| 312 | static int __init tc2_pm_init(void) | 313 | static int __init tc2_pm_init(void) |
| 313 | { | 314 | { |
| 314 | int ret; | 315 | int ret, irq; |
| 315 | void __iomem *scc; | 316 | void __iomem *scc; |
| 316 | u32 a15_cluster_id, a7_cluster_id, sys_info; | 317 | u32 a15_cluster_id, a7_cluster_id, sys_info; |
| 317 | struct device_node *np; | 318 | struct device_node *np; |
| @@ -336,13 +337,15 @@ static int __init tc2_pm_init(void) | |||
| 336 | tc2_nr_cpus[a15_cluster_id] = (sys_info >> 16) & 0xf; | 337 | tc2_nr_cpus[a15_cluster_id] = (sys_info >> 16) & 0xf; |
| 337 | tc2_nr_cpus[a7_cluster_id] = (sys_info >> 20) & 0xf; | 338 | tc2_nr_cpus[a7_cluster_id] = (sys_info >> 20) & 0xf; |
| 338 | 339 | ||
| 340 | irq = irq_of_parse_and_map(np, 0); | ||
| 341 | |||
| 339 | /* | 342 | /* |
| 340 | * A subset of the SCC registers is also used to communicate | 343 | * A subset of the SCC registers is also used to communicate |
| 341 | * with the SPC (power controller). We need to be able to | 344 | * with the SPC (power controller). We need to be able to |
| 342 | * drive it very early in the boot process to power up | 345 | * drive it very early in the boot process to power up |
| 343 | * processors, so we initialize the SPC driver here. | 346 | * processors, so we initialize the SPC driver here. |
| 344 | */ | 347 | */ |
| 345 | ret = ve_spc_init(scc + SPC_BASE, a15_cluster_id); | 348 | ret = ve_spc_init(scc + SPC_BASE, a15_cluster_id, irq); |
| 346 | if (ret) | 349 | if (ret) |
| 347 | return ret; | 350 | return ret; |
| 348 | 351 | ||
diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm index 701ec95ce954..ce52ed949249 100644 --- a/drivers/cpufreq/Kconfig.arm +++ b/drivers/cpufreq/Kconfig.arm | |||
| @@ -224,3 +224,11 @@ config ARM_TEGRA_CPUFREQ | |||
| 224 | default y | 224 | default y |
| 225 | help | 225 | help |
| 226 | This adds the CPUFreq driver support for TEGRA SOCs. | 226 | This adds the CPUFreq driver support for TEGRA SOCs. |
| 227 | |||
| 228 | config ARM_VEXPRESS_SPC_CPUFREQ | ||
| 229 | tristate "Versatile Express SPC based CPUfreq driver" | ||
| 230 | select ARM_BIG_LITTLE_CPUFREQ | ||
| 231 | depends on ARCH_VEXPRESS_SPC | ||
| 232 | help | ||
| 233 | This add the CPUfreq driver support for Versatile Express | ||
| 234 | big.LITTLE platforms using SPC for power management. | ||
diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile index b7948bbbbf1f..74945652dd7a 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile | |||
| @@ -74,6 +74,7 @@ obj-$(CONFIG_ARM_SA1100_CPUFREQ) += sa1100-cpufreq.o | |||
| 74 | obj-$(CONFIG_ARM_SA1110_CPUFREQ) += sa1110-cpufreq.o | 74 | obj-$(CONFIG_ARM_SA1110_CPUFREQ) += sa1110-cpufreq.o |
| 75 | obj-$(CONFIG_ARM_SPEAR_CPUFREQ) += spear-cpufreq.o | 75 | obj-$(CONFIG_ARM_SPEAR_CPUFREQ) += spear-cpufreq.o |
| 76 | obj-$(CONFIG_ARM_TEGRA_CPUFREQ) += tegra-cpufreq.o | 76 | obj-$(CONFIG_ARM_TEGRA_CPUFREQ) += tegra-cpufreq.o |
| 77 | obj-$(CONFIG_ARM_VEXPRESS_SPC_CPUFREQ) += vexpress-spc-cpufreq.o | ||
| 77 | 78 | ||
| 78 | ################################################################################## | 79 | ################################################################################## |
| 79 | # PowerPC platform drivers | 80 | # PowerPC platform drivers |
diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c index e4bc19552d2b..caf41ebea184 100644 --- a/drivers/cpufreq/acpi-cpufreq.c +++ b/drivers/cpufreq/acpi-cpufreq.c | |||
| @@ -428,14 +428,10 @@ static int acpi_cpufreq_target(struct cpufreq_policy *policy, | |||
| 428 | { | 428 | { |
| 429 | struct acpi_cpufreq_data *data = per_cpu(acfreq_data, policy->cpu); | 429 | struct acpi_cpufreq_data *data = per_cpu(acfreq_data, policy->cpu); |
| 430 | struct acpi_processor_performance *perf; | 430 | struct acpi_processor_performance *perf; |
| 431 | struct cpufreq_freqs freqs; | ||
| 432 | struct drv_cmd cmd; | 431 | struct drv_cmd cmd; |
| 433 | unsigned int next_perf_state = 0; /* Index into perf table */ | 432 | unsigned int next_perf_state = 0; /* Index into perf table */ |
| 434 | int result = 0; | 433 | int result = 0; |
| 435 | 434 | ||
| 436 | pr_debug("acpi_cpufreq_target %d (%d)\n", | ||
| 437 | data->freq_table[index].frequency, policy->cpu); | ||
| 438 | |||
| 439 | if (unlikely(data == NULL || | 435 | if (unlikely(data == NULL || |
| 440 | data->acpi_data == NULL || data->freq_table == NULL)) { | 436 | data->acpi_data == NULL || data->freq_table == NULL)) { |
| 441 | return -ENODEV; | 437 | return -ENODEV; |
| @@ -483,23 +479,17 @@ static int acpi_cpufreq_target(struct cpufreq_policy *policy, | |||
| 483 | else | 479 | else |
| 484 | cmd.mask = cpumask_of(policy->cpu); | 480 | cmd.mask = cpumask_of(policy->cpu); |
| 485 | 481 | ||
| 486 | freqs.old = perf->states[perf->state].core_frequency * 1000; | ||
| 487 | freqs.new = data->freq_table[index].frequency; | ||
| 488 | cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); | ||
| 489 | |||
| 490 | drv_write(&cmd); | 482 | drv_write(&cmd); |
| 491 | 483 | ||
| 492 | if (acpi_pstate_strict) { | 484 | if (acpi_pstate_strict) { |
| 493 | if (!check_freqs(cmd.mask, freqs.new, data)) { | 485 | if (!check_freqs(cmd.mask, data->freq_table[index].frequency, |
| 486 | data)) { | ||
| 494 | pr_debug("acpi_cpufreq_target failed (%d)\n", | 487 | pr_debug("acpi_cpufreq_target failed (%d)\n", |
| 495 | policy->cpu); | 488 | policy->cpu); |
| 496 | result = -EAGAIN; | 489 | result = -EAGAIN; |
| 497 | freqs.new = freqs.old; | ||
| 498 | } | 490 | } |
| 499 | } | 491 | } |
| 500 | 492 | ||
| 501 | cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); | ||
| 502 | |||
| 503 | if (!result) | 493 | if (!result) |
| 504 | perf->state = next_perf_state; | 494 | perf->state = next_perf_state; |
| 505 | 495 | ||
diff --git a/drivers/cpufreq/arm_big_little.c b/drivers/cpufreq/arm_big_little.c index 163e3378fe17..5519933813ea 100644 --- a/drivers/cpufreq/arm_big_little.c +++ b/drivers/cpufreq/arm_big_little.c | |||
| @@ -24,91 +24,319 @@ | |||
| 24 | #include <linux/cpufreq.h> | 24 | #include <linux/cpufreq.h> |
| 25 | #include <linux/cpumask.h> | 25 | #include <linux/cpumask.h> |
| 26 | #include <linux/export.h> | 26 | #include <linux/export.h> |
| 27 | #include <linux/mutex.h> | ||
| 27 | #include <linux/of_platform.h> | 28 | #include <linux/of_platform.h> |
| 28 | #include <linux/pm_opp.h> | 29 | #include <linux/pm_opp.h> |
| 29 | #include <linux/slab.h> | 30 | #include <linux/slab.h> |
| 30 | #include <linux/topology.h> | 31 | #include <linux/topology.h> |
| 31 | #include <linux/types.h> | 32 | #include <linux/types.h> |
| 33 | #include <asm/bL_switcher.h> | ||
| 32 | 34 | ||
| 33 | #include "arm_big_little.h" | 35 | #include "arm_big_little.h" |
| 34 | 36 | ||
| 35 | /* Currently we support only two clusters */ | 37 | /* Currently we support only two clusters */ |
| 38 | #define A15_CLUSTER 0 | ||
| 39 | #define A7_CLUSTER 1 | ||
| 36 | #define MAX_CLUSTERS 2 | 40 | #define MAX_CLUSTERS 2 |
| 37 | 41 | ||
| 42 | #ifdef CONFIG_BL_SWITCHER | ||
| 43 | static bool bL_switching_enabled; | ||
| 44 | #define is_bL_switching_enabled() bL_switching_enabled | ||
| 45 | #define set_switching_enabled(x) (bL_switching_enabled = (x)) | ||
| 46 | #else | ||
| 47 | #define is_bL_switching_enabled() false | ||
| 48 | #define set_switching_enabled(x) do { } while (0) | ||
| 49 | #endif | ||
| 50 | |||
| 51 | #define ACTUAL_FREQ(cluster, freq) ((cluster == A7_CLUSTER) ? freq << 1 : freq) | ||
| 52 | #define VIRT_FREQ(cluster, freq) ((cluster == A7_CLUSTER) ? freq >> 1 : freq) | ||
| 53 | |||
| 38 | static struct cpufreq_arm_bL_ops *arm_bL_ops; | 54 | static struct cpufreq_arm_bL_ops *arm_bL_ops; |
| 39 | static struct clk *clk[MAX_CLUSTERS]; | 55 | static struct clk *clk[MAX_CLUSTERS]; |
| 40 | static struct cpufreq_frequency_table *freq_table[MAX_CLUSTERS]; | 56 | static struct cpufreq_frequency_table *freq_table[MAX_CLUSTERS + 1]; |
| 41 | static atomic_t cluster_usage[MAX_CLUSTERS] = {ATOMIC_INIT(0), ATOMIC_INIT(0)}; | 57 | static atomic_t cluster_usage[MAX_CLUSTERS + 1]; |
| 58 | |||
| 59 | static unsigned int clk_big_min; /* (Big) clock frequencies */ | ||
| 60 | static unsigned int clk_little_max; /* Maximum clock frequency (Little) */ | ||
| 61 | |||
| 62 | static DEFINE_PER_CPU(unsigned int, physical_cluster); | ||
| 63 | static DEFINE_PER_CPU(unsigned int, cpu_last_req_freq); | ||
| 64 | |||
| 65 | static struct mutex cluster_lock[MAX_CLUSTERS]; | ||
| 66 | |||
| 67 | static inline int raw_cpu_to_cluster(int cpu) | ||
| 68 | { | ||
| 69 | return topology_physical_package_id(cpu); | ||
| 70 | } | ||
| 71 | |||
| 72 | static inline int cpu_to_cluster(int cpu) | ||
| 73 | { | ||
| 74 | return is_bL_switching_enabled() ? | ||
| 75 | MAX_CLUSTERS : raw_cpu_to_cluster(cpu); | ||
| 76 | } | ||
| 77 | |||
| 78 | static unsigned int find_cluster_maxfreq(int cluster) | ||
| 79 | { | ||
| 80 | int j; | ||
| 81 | u32 max_freq = 0, cpu_freq; | ||
| 82 | |||
| 83 | for_each_online_cpu(j) { | ||
| 84 | cpu_freq = per_cpu(cpu_last_req_freq, j); | ||
| 85 | |||
| 86 | if ((cluster == per_cpu(physical_cluster, j)) && | ||
| 87 | (max_freq < cpu_freq)) | ||
| 88 | max_freq = cpu_freq; | ||
| 89 | } | ||
| 90 | |||
| 91 | pr_debug("%s: cluster: %d, max freq: %d\n", __func__, cluster, | ||
| 92 | max_freq); | ||
| 93 | |||
| 94 | return max_freq; | ||
| 95 | } | ||
| 96 | |||
| 97 | static unsigned int clk_get_cpu_rate(unsigned int cpu) | ||
| 98 | { | ||
| 99 | u32 cur_cluster = per_cpu(physical_cluster, cpu); | ||
| 100 | u32 rate = clk_get_rate(clk[cur_cluster]) / 1000; | ||
| 101 | |||
| 102 | /* For switcher we use virtual A7 clock rates */ | ||
| 103 | if (is_bL_switching_enabled()) | ||
| 104 | rate = VIRT_FREQ(cur_cluster, rate); | ||
| 105 | |||
| 106 | pr_debug("%s: cpu: %d, cluster: %d, freq: %u\n", __func__, cpu, | ||
| 107 | cur_cluster, rate); | ||
| 108 | |||
| 109 | return rate; | ||
| 110 | } | ||
| 111 | |||
| 112 | static unsigned int bL_cpufreq_get_rate(unsigned int cpu) | ||
| 113 | { | ||
| 114 | if (is_bL_switching_enabled()) { | ||
| 115 | pr_debug("%s: freq: %d\n", __func__, per_cpu(cpu_last_req_freq, | ||
| 116 | cpu)); | ||
| 117 | |||
| 118 | return per_cpu(cpu_last_req_freq, cpu); | ||
| 119 | } else { | ||
| 120 | return clk_get_cpu_rate(cpu); | ||
| 121 | } | ||
| 122 | } | ||
| 42 | 123 | ||
| 43 | static unsigned int bL_cpufreq_get(unsigned int cpu) | 124 | static unsigned int |
| 125 | bL_cpufreq_set_rate(u32 cpu, u32 old_cluster, u32 new_cluster, u32 rate) | ||
| 44 | { | 126 | { |
| 45 | u32 cur_cluster = cpu_to_cluster(cpu); | 127 | u32 new_rate, prev_rate; |
| 128 | int ret; | ||
| 129 | bool bLs = is_bL_switching_enabled(); | ||
| 130 | |||
| 131 | mutex_lock(&cluster_lock[new_cluster]); | ||
| 132 | |||
| 133 | if (bLs) { | ||
| 134 | prev_rate = per_cpu(cpu_last_req_freq, cpu); | ||
| 135 | per_cpu(cpu_last_req_freq, cpu) = rate; | ||
| 136 | per_cpu(physical_cluster, cpu) = new_cluster; | ||
| 137 | |||
| 138 | new_rate = find_cluster_maxfreq(new_cluster); | ||
| 139 | new_rate = ACTUAL_FREQ(new_cluster, new_rate); | ||
| 140 | } else { | ||
| 141 | new_rate = rate; | ||
| 142 | } | ||
| 143 | |||
| 144 | pr_debug("%s: cpu: %d, old cluster: %d, new cluster: %d, freq: %d\n", | ||
| 145 | __func__, cpu, old_cluster, new_cluster, new_rate); | ||
| 146 | |||
| 147 | ret = clk_set_rate(clk[new_cluster], new_rate * 1000); | ||
| 148 | if (WARN_ON(ret)) { | ||
| 149 | pr_err("clk_set_rate failed: %d, new cluster: %d\n", ret, | ||
| 150 | new_cluster); | ||
| 151 | if (bLs) { | ||
| 152 | per_cpu(cpu_last_req_freq, cpu) = prev_rate; | ||
| 153 | per_cpu(physical_cluster, cpu) = old_cluster; | ||
| 154 | } | ||
| 155 | |||
| 156 | mutex_unlock(&cluster_lock[new_cluster]); | ||
| 157 | |||
| 158 | return ret; | ||
| 159 | } | ||
| 160 | |||
| 161 | mutex_unlock(&cluster_lock[new_cluster]); | ||
| 162 | |||
| 163 | /* Recalc freq for old cluster when switching clusters */ | ||
| 164 | if (old_cluster != new_cluster) { | ||
| 165 | pr_debug("%s: cpu: %d, old cluster: %d, new cluster: %d\n", | ||
| 166 | __func__, cpu, old_cluster, new_cluster); | ||
| 167 | |||
| 168 | /* Switch cluster */ | ||
| 169 | bL_switch_request(cpu, new_cluster); | ||
| 170 | |||
| 171 | mutex_lock(&cluster_lock[old_cluster]); | ||
| 46 | 172 | ||
| 47 | return clk_get_rate(clk[cur_cluster]) / 1000; | 173 | /* Set freq of old cluster if there are cpus left on it */ |
| 174 | new_rate = find_cluster_maxfreq(old_cluster); | ||
| 175 | new_rate = ACTUAL_FREQ(old_cluster, new_rate); | ||
| 176 | |||
| 177 | if (new_rate) { | ||
| 178 | pr_debug("%s: Updating rate of old cluster: %d, to freq: %d\n", | ||
| 179 | __func__, old_cluster, new_rate); | ||
| 180 | |||
| 181 | if (clk_set_rate(clk[old_cluster], new_rate * 1000)) | ||
| 182 | pr_err("%s: clk_set_rate failed: %d, old cluster: %d\n", | ||
| 183 | __func__, ret, old_cluster); | ||
| 184 | } | ||
| 185 | mutex_unlock(&cluster_lock[old_cluster]); | ||
| 186 | } | ||
| 187 | |||
| 188 | return 0; | ||
| 48 | } | 189 | } |
| 49 | 190 | ||
| 50 | /* Set clock frequency */ | 191 | /* Set clock frequency */ |
| 51 | static int bL_cpufreq_set_target(struct cpufreq_policy *policy, | 192 | static int bL_cpufreq_set_target(struct cpufreq_policy *policy, |
| 52 | unsigned int index) | 193 | unsigned int index) |
| 53 | { | 194 | { |
| 54 | struct cpufreq_freqs freqs; | 195 | u32 cpu = policy->cpu, cur_cluster, new_cluster, actual_cluster; |
| 55 | u32 cpu = policy->cpu, cur_cluster; | 196 | unsigned int freqs_new; |
| 56 | int ret = 0; | 197 | |
| 198 | cur_cluster = cpu_to_cluster(cpu); | ||
| 199 | new_cluster = actual_cluster = per_cpu(physical_cluster, cpu); | ||
| 200 | |||
| 201 | freqs_new = freq_table[cur_cluster][index].frequency; | ||
| 202 | |||
| 203 | if (is_bL_switching_enabled()) { | ||
| 204 | if ((actual_cluster == A15_CLUSTER) && | ||
| 205 | (freqs_new < clk_big_min)) { | ||
| 206 | new_cluster = A7_CLUSTER; | ||
| 207 | } else if ((actual_cluster == A7_CLUSTER) && | ||
| 208 | (freqs_new > clk_little_max)) { | ||
| 209 | new_cluster = A15_CLUSTER; | ||
| 210 | } | ||
| 211 | } | ||
| 57 | 212 | ||
| 58 | cur_cluster = cpu_to_cluster(policy->cpu); | 213 | return bL_cpufreq_set_rate(cpu, actual_cluster, new_cluster, freqs_new); |
| 214 | } | ||
| 59 | 215 | ||
| 60 | freqs.old = bL_cpufreq_get(policy->cpu); | 216 | static inline u32 get_table_count(struct cpufreq_frequency_table *table) |
| 61 | freqs.new = freq_table[cur_cluster][index].frequency; | 217 | { |
| 218 | int count; | ||
| 62 | 219 | ||
| 63 | pr_debug("%s: cpu: %d, cluster: %d, oldfreq: %d, target freq: %d, new freq: %d\n", | 220 | for (count = 0; table[count].frequency != CPUFREQ_TABLE_END; count++) |
| 64 | __func__, cpu, cur_cluster, freqs.old, freqs.new, | 221 | ; |
| 65 | freqs.new); | ||
| 66 | 222 | ||
| 67 | cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); | 223 | return count; |
| 224 | } | ||
| 68 | 225 | ||
| 69 | ret = clk_set_rate(clk[cur_cluster], freqs.new * 1000); | 226 | /* get the minimum frequency in the cpufreq_frequency_table */ |
| 70 | if (ret) { | 227 | static inline u32 get_table_min(struct cpufreq_frequency_table *table) |
| 71 | pr_err("clk_set_rate failed: %d\n", ret); | 228 | { |
| 72 | freqs.new = freqs.old; | 229 | int i; |
| 230 | uint32_t min_freq = ~0; | ||
| 231 | for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) | ||
| 232 | if (table[i].frequency < min_freq) | ||
| 233 | min_freq = table[i].frequency; | ||
| 234 | return min_freq; | ||
| 235 | } | ||
| 236 | |||
| 237 | /* get the maximum frequency in the cpufreq_frequency_table */ | ||
| 238 | static inline u32 get_table_max(struct cpufreq_frequency_table *table) | ||
| 239 | { | ||
| 240 | int i; | ||
| 241 | uint32_t max_freq = 0; | ||
| 242 | for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) | ||
| 243 | if (table[i].frequency > max_freq) | ||
| 244 | max_freq = table[i].frequency; | ||
| 245 | return max_freq; | ||
| 246 | } | ||
| 247 | |||
| 248 | static int merge_cluster_tables(void) | ||
| 249 | { | ||
| 250 | int i, j, k = 0, count = 1; | ||
| 251 | struct cpufreq_frequency_table *table; | ||
| 252 | |||
| 253 | for (i = 0; i < MAX_CLUSTERS; i++) | ||
| 254 | count += get_table_count(freq_table[i]); | ||
| 255 | |||
| 256 | table = kzalloc(sizeof(*table) * count, GFP_KERNEL); | ||
| 257 | if (!table) | ||
| 258 | return -ENOMEM; | ||
| 259 | |||
| 260 | freq_table[MAX_CLUSTERS] = table; | ||
| 261 | |||
| 262 | /* Add in reverse order to get freqs in increasing order */ | ||
| 263 | for (i = MAX_CLUSTERS - 1; i >= 0; i--) { | ||
| 264 | for (j = 0; freq_table[i][j].frequency != CPUFREQ_TABLE_END; | ||
| 265 | j++) { | ||
| 266 | table[k].frequency = VIRT_FREQ(i, | ||
| 267 | freq_table[i][j].frequency); | ||
| 268 | pr_debug("%s: index: %d, freq: %d\n", __func__, k, | ||
| 269 | table[k].frequency); | ||
| 270 | k++; | ||
| 271 | } | ||
| 73 | } | 272 | } |
| 74 | 273 | ||
| 75 | cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); | 274 | table[k].driver_data = k; |
| 275 | table[k].frequency = CPUFREQ_TABLE_END; | ||
| 76 | 276 | ||
| 77 | return ret; | 277 | pr_debug("%s: End, table: %p, count: %d\n", __func__, table, k); |
| 278 | |||
| 279 | return 0; | ||
| 280 | } | ||
| 281 | |||
| 282 | static void _put_cluster_clk_and_freq_table(struct device *cpu_dev) | ||
| 283 | { | ||
| 284 | u32 cluster = raw_cpu_to_cluster(cpu_dev->id); | ||
| 285 | |||
| 286 | if (!freq_table[cluster]) | ||
| 287 | return; | ||
| 288 | |||
| 289 | clk_put(clk[cluster]); | ||
| 290 | dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table[cluster]); | ||
| 291 | dev_dbg(cpu_dev, "%s: cluster: %d\n", __func__, cluster); | ||
| 78 | } | 292 | } |
| 79 | 293 | ||
| 80 | static void put_cluster_clk_and_freq_table(struct device *cpu_dev) | 294 | static void put_cluster_clk_and_freq_table(struct device *cpu_dev) |
| 81 | { | 295 | { |
| 82 | u32 cluster = cpu_to_cluster(cpu_dev->id); | 296 | u32 cluster = cpu_to_cluster(cpu_dev->id); |
| 297 | int i; | ||
| 298 | |||
| 299 | if (atomic_dec_return(&cluster_usage[cluster])) | ||
| 300 | return; | ||
| 301 | |||
| 302 | if (cluster < MAX_CLUSTERS) | ||
| 303 | return _put_cluster_clk_and_freq_table(cpu_dev); | ||
| 304 | |||
| 305 | for_each_present_cpu(i) { | ||
| 306 | struct device *cdev = get_cpu_device(i); | ||
| 307 | if (!cdev) { | ||
| 308 | pr_err("%s: failed to get cpu%d device\n", __func__, i); | ||
| 309 | return; | ||
| 310 | } | ||
| 83 | 311 | ||
| 84 | if (!atomic_dec_return(&cluster_usage[cluster])) { | 312 | _put_cluster_clk_and_freq_table(cdev); |
| 85 | clk_put(clk[cluster]); | ||
| 86 | dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table[cluster]); | ||
| 87 | dev_dbg(cpu_dev, "%s: cluster: %d\n", __func__, cluster); | ||
| 88 | } | 313 | } |
| 314 | |||
| 315 | /* free virtual table */ | ||
| 316 | kfree(freq_table[cluster]); | ||
| 89 | } | 317 | } |
| 90 | 318 | ||
| 91 | static int get_cluster_clk_and_freq_table(struct device *cpu_dev) | 319 | static int _get_cluster_clk_and_freq_table(struct device *cpu_dev) |
| 92 | { | 320 | { |
| 93 | u32 cluster = cpu_to_cluster(cpu_dev->id); | 321 | u32 cluster = raw_cpu_to_cluster(cpu_dev->id); |
| 94 | char name[14] = "cpu-cluster."; | 322 | char name[14] = "cpu-cluster."; |
| 95 | int ret; | 323 | int ret; |
| 96 | 324 | ||
| 97 | if (atomic_inc_return(&cluster_usage[cluster]) != 1) | 325 | if (freq_table[cluster]) |
| 98 | return 0; | 326 | return 0; |
| 99 | 327 | ||
| 100 | ret = arm_bL_ops->init_opp_table(cpu_dev); | 328 | ret = arm_bL_ops->init_opp_table(cpu_dev); |
| 101 | if (ret) { | 329 | if (ret) { |
| 102 | dev_err(cpu_dev, "%s: init_opp_table failed, cpu: %d, err: %d\n", | 330 | dev_err(cpu_dev, "%s: init_opp_table failed, cpu: %d, err: %d\n", |
| 103 | __func__, cpu_dev->id, ret); | 331 | __func__, cpu_dev->id, ret); |
| 104 | goto atomic_dec; | 332 | goto out; |
| 105 | } | 333 | } |
| 106 | 334 | ||
| 107 | ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table[cluster]); | 335 | ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table[cluster]); |
| 108 | if (ret) { | 336 | if (ret) { |
| 109 | dev_err(cpu_dev, "%s: failed to init cpufreq table, cpu: %d, err: %d\n", | 337 | dev_err(cpu_dev, "%s: failed to init cpufreq table, cpu: %d, err: %d\n", |
| 110 | __func__, cpu_dev->id, ret); | 338 | __func__, cpu_dev->id, ret); |
| 111 | goto atomic_dec; | 339 | goto out; |
| 112 | } | 340 | } |
| 113 | 341 | ||
| 114 | name[12] = cluster + '0'; | 342 | name[12] = cluster + '0'; |
| @@ -125,13 +353,72 @@ static int get_cluster_clk_and_freq_table(struct device *cpu_dev) | |||
| 125 | ret = PTR_ERR(clk[cluster]); | 353 | ret = PTR_ERR(clk[cluster]); |
| 126 | dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table[cluster]); | 354 | dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table[cluster]); |
| 127 | 355 | ||
| 128 | atomic_dec: | 356 | out: |
| 129 | atomic_dec(&cluster_usage[cluster]); | ||
| 130 | dev_err(cpu_dev, "%s: Failed to get data for cluster: %d\n", __func__, | 357 | dev_err(cpu_dev, "%s: Failed to get data for cluster: %d\n", __func__, |
| 131 | cluster); | 358 | cluster); |
| 132 | return ret; | 359 | return ret; |
| 133 | } | 360 | } |
| 134 | 361 | ||
| 362 | static int get_cluster_clk_and_freq_table(struct device *cpu_dev) | ||
| 363 | { | ||
| 364 | u32 cluster = cpu_to_cluster(cpu_dev->id); | ||
| 365 | int i, ret; | ||
| 366 | |||
| 367 | if (atomic_inc_return(&cluster_usage[cluster]) != 1) | ||
| 368 | return 0; | ||
| 369 | |||
| 370 | if (cluster < MAX_CLUSTERS) { | ||
| 371 | ret = _get_cluster_clk_and_freq_table(cpu_dev); | ||
| 372 | if (ret) | ||
| 373 | atomic_dec(&cluster_usage[cluster]); | ||
| 374 | return ret; | ||
| 375 | } | ||
| 376 | |||
| 377 | /* | ||
| 378 | * Get data for all clusters and fill virtual cluster with a merge of | ||
| 379 | * both | ||
| 380 | */ | ||
| 381 | for_each_present_cpu(i) { | ||
| 382 | struct device *cdev = get_cpu_device(i); | ||
| 383 | if (!cdev) { | ||
| 384 | pr_err("%s: failed to get cpu%d device\n", __func__, i); | ||
| 385 | return -ENODEV; | ||
| 386 | } | ||
| 387 | |||
| 388 | ret = _get_cluster_clk_and_freq_table(cdev); | ||
| 389 | if (ret) | ||
| 390 | goto put_clusters; | ||
| 391 | } | ||
| 392 | |||
| 393 | ret = merge_cluster_tables(); | ||
| 394 | if (ret) | ||
| 395 | goto put_clusters; | ||
| 396 | |||
| 397 | /* Assuming 2 cluster, set clk_big_min and clk_little_max */ | ||
| 398 | clk_big_min = get_table_min(freq_table[0]); | ||
| 399 | clk_little_max = VIRT_FREQ(1, get_table_max(freq_table[1])); | ||
| 400 | |||
| 401 | pr_debug("%s: cluster: %d, clk_big_min: %d, clk_little_max: %d\n", | ||
| 402 | __func__, cluster, clk_big_min, clk_little_max); | ||
| 403 | |||
| 404 | return 0; | ||
| 405 | |||
| 406 | put_clusters: | ||
| 407 | for_each_present_cpu(i) { | ||
| 408 | struct device *cdev = get_cpu_device(i); | ||
| 409 | if (!cdev) { | ||
| 410 | pr_err("%s: failed to get cpu%d device\n", __func__, i); | ||
| 411 | return -ENODEV; | ||
| 412 | } | ||
| 413 | |||
| 414 | _put_cluster_clk_and_freq_table(cdev); | ||
| 415 | } | ||
| 416 | |||
| 417 | atomic_dec(&cluster_usage[cluster]); | ||
| 418 | |||
| 419 | return ret; | ||
| 420 | } | ||
| 421 | |||
| 135 | /* Per-CPU initialization */ | 422 | /* Per-CPU initialization */ |
| 136 | static int bL_cpufreq_init(struct cpufreq_policy *policy) | 423 | static int bL_cpufreq_init(struct cpufreq_policy *policy) |
| 137 | { | 424 | { |
| @@ -158,13 +445,23 @@ static int bL_cpufreq_init(struct cpufreq_policy *policy) | |||
| 158 | return ret; | 445 | return ret; |
| 159 | } | 446 | } |
| 160 | 447 | ||
| 448 | if (cur_cluster < MAX_CLUSTERS) { | ||
| 449 | cpumask_copy(policy->cpus, topology_core_cpumask(policy->cpu)); | ||
| 450 | |||
| 451 | per_cpu(physical_cluster, policy->cpu) = cur_cluster; | ||
| 452 | } else { | ||
| 453 | /* Assumption: during init, we are always running on A15 */ | ||
| 454 | per_cpu(physical_cluster, policy->cpu) = A15_CLUSTER; | ||
| 455 | } | ||
| 456 | |||
| 161 | if (arm_bL_ops->get_transition_latency) | 457 | if (arm_bL_ops->get_transition_latency) |
| 162 | policy->cpuinfo.transition_latency = | 458 | policy->cpuinfo.transition_latency = |
| 163 | arm_bL_ops->get_transition_latency(cpu_dev); | 459 | arm_bL_ops->get_transition_latency(cpu_dev); |
| 164 | else | 460 | else |
| 165 | policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; | 461 | policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; |
| 166 | 462 | ||
| 167 | cpumask_copy(policy->cpus, topology_core_cpumask(policy->cpu)); | 463 | if (is_bL_switching_enabled()) |
| 464 | per_cpu(cpu_last_req_freq, policy->cpu) = clk_get_cpu_rate(policy->cpu); | ||
| 168 | 465 | ||
| 169 | dev_info(cpu_dev, "%s: CPU %d initialized\n", __func__, policy->cpu); | 466 | dev_info(cpu_dev, "%s: CPU %d initialized\n", __func__, policy->cpu); |
| 170 | return 0; | 467 | return 0; |
| @@ -194,15 +491,47 @@ static struct cpufreq_driver bL_cpufreq_driver = { | |||
| 194 | CPUFREQ_HAVE_GOVERNOR_PER_POLICY, | 491 | CPUFREQ_HAVE_GOVERNOR_PER_POLICY, |
| 195 | .verify = cpufreq_generic_frequency_table_verify, | 492 | .verify = cpufreq_generic_frequency_table_verify, |
| 196 | .target_index = bL_cpufreq_set_target, | 493 | .target_index = bL_cpufreq_set_target, |
| 197 | .get = bL_cpufreq_get, | 494 | .get = bL_cpufreq_get_rate, |
| 198 | .init = bL_cpufreq_init, | 495 | .init = bL_cpufreq_init, |
| 199 | .exit = bL_cpufreq_exit, | 496 | .exit = bL_cpufreq_exit, |
| 200 | .attr = cpufreq_generic_attr, | 497 | .attr = cpufreq_generic_attr, |
| 201 | }; | 498 | }; |
| 202 | 499 | ||
| 500 | static int bL_cpufreq_switcher_notifier(struct notifier_block *nfb, | ||
| 501 | unsigned long action, void *_arg) | ||
| 502 | { | ||
| 503 | pr_debug("%s: action: %ld\n", __func__, action); | ||
| 504 | |||
| 505 | switch (action) { | ||
| 506 | case BL_NOTIFY_PRE_ENABLE: | ||
| 507 | case BL_NOTIFY_PRE_DISABLE: | ||
| 508 | cpufreq_unregister_driver(&bL_cpufreq_driver); | ||
| 509 | break; | ||
| 510 | |||
| 511 | case BL_NOTIFY_POST_ENABLE: | ||
| 512 | set_switching_enabled(true); | ||
| 513 | cpufreq_register_driver(&bL_cpufreq_driver); | ||
| 514 | break; | ||
| 515 | |||
| 516 | case BL_NOTIFY_POST_DISABLE: | ||
| 517 | set_switching_enabled(false); | ||
| 518 | cpufreq_register_driver(&bL_cpufreq_driver); | ||
| 519 | break; | ||
| 520 | |||
| 521 | default: | ||
| 522 | return NOTIFY_DONE; | ||
| 523 | } | ||
| 524 | |||
| 525 | return NOTIFY_OK; | ||
| 526 | } | ||
| 527 | |||
| 528 | static struct notifier_block bL_switcher_notifier = { | ||
| 529 | .notifier_call = bL_cpufreq_switcher_notifier, | ||
| 530 | }; | ||
| 531 | |||
| 203 | int bL_cpufreq_register(struct cpufreq_arm_bL_ops *ops) | 532 | int bL_cpufreq_register(struct cpufreq_arm_bL_ops *ops) |
| 204 | { | 533 | { |
| 205 | int ret; | 534 | int ret, i; |
| 206 | 535 | ||
| 207 | if (arm_bL_ops) { | 536 | if (arm_bL_ops) { |
| 208 | pr_debug("%s: Already registered: %s, exiting\n", __func__, | 537 | pr_debug("%s: Already registered: %s, exiting\n", __func__, |
| @@ -217,16 +546,29 @@ int bL_cpufreq_register(struct cpufreq_arm_bL_ops *ops) | |||
| 217 | 546 | ||
| 218 | arm_bL_ops = ops; | 547 | arm_bL_ops = ops; |
| 219 | 548 | ||
| 549 | ret = bL_switcher_get_enabled(); | ||
| 550 | set_switching_enabled(ret); | ||
| 551 | |||
| 552 | for (i = 0; i < MAX_CLUSTERS; i++) | ||
| 553 | mutex_init(&cluster_lock[i]); | ||
| 554 | |||
| 220 | ret = cpufreq_register_driver(&bL_cpufreq_driver); | 555 | ret = cpufreq_register_driver(&bL_cpufreq_driver); |
| 221 | if (ret) { | 556 | if (ret) { |
| 222 | pr_info("%s: Failed registering platform driver: %s, err: %d\n", | 557 | pr_info("%s: Failed registering platform driver: %s, err: %d\n", |
| 223 | __func__, ops->name, ret); | 558 | __func__, ops->name, ret); |
| 224 | arm_bL_ops = NULL; | 559 | arm_bL_ops = NULL; |
| 225 | } else { | 560 | } else { |
| 226 | pr_info("%s: Registered platform driver: %s\n", __func__, | 561 | ret = bL_switcher_register_notifier(&bL_switcher_notifier); |
| 227 | ops->name); | 562 | if (ret) { |
| 563 | cpufreq_unregister_driver(&bL_cpufreq_driver); | ||
| 564 | arm_bL_ops = NULL; | ||
| 565 | } else { | ||
| 566 | pr_info("%s: Registered platform driver: %s\n", | ||
| 567 | __func__, ops->name); | ||
| 568 | } | ||
| 228 | } | 569 | } |
| 229 | 570 | ||
| 571 | bL_switcher_put_enabled(); | ||
| 230 | return ret; | 572 | return ret; |
| 231 | } | 573 | } |
| 232 | EXPORT_SYMBOL_GPL(bL_cpufreq_register); | 574 | EXPORT_SYMBOL_GPL(bL_cpufreq_register); |
| @@ -239,7 +581,10 @@ void bL_cpufreq_unregister(struct cpufreq_arm_bL_ops *ops) | |||
| 239 | return; | 581 | return; |
| 240 | } | 582 | } |
| 241 | 583 | ||
| 584 | bL_switcher_get_enabled(); | ||
| 585 | bL_switcher_unregister_notifier(&bL_switcher_notifier); | ||
| 242 | cpufreq_unregister_driver(&bL_cpufreq_driver); | 586 | cpufreq_unregister_driver(&bL_cpufreq_driver); |
| 587 | bL_switcher_put_enabled(); | ||
| 243 | pr_info("%s: Un-registered platform driver: %s\n", __func__, | 588 | pr_info("%s: Un-registered platform driver: %s\n", __func__, |
| 244 | arm_bL_ops->name); | 589 | arm_bL_ops->name); |
| 245 | arm_bL_ops = NULL; | 590 | arm_bL_ops = NULL; |
diff --git a/drivers/cpufreq/arm_big_little.h b/drivers/cpufreq/arm_big_little.h index 79b2ce17884d..70f18fc12d4a 100644 --- a/drivers/cpufreq/arm_big_little.h +++ b/drivers/cpufreq/arm_big_little.h | |||
| @@ -34,11 +34,6 @@ struct cpufreq_arm_bL_ops { | |||
| 34 | int (*init_opp_table)(struct device *cpu_dev); | 34 | int (*init_opp_table)(struct device *cpu_dev); |
| 35 | }; | 35 | }; |
| 36 | 36 | ||
| 37 | static inline int cpu_to_cluster(int cpu) | ||
| 38 | { | ||
| 39 | return topology_physical_package_id(cpu); | ||
| 40 | } | ||
| 41 | |||
| 42 | int bL_cpufreq_register(struct cpufreq_arm_bL_ops *ops); | 37 | int bL_cpufreq_register(struct cpufreq_arm_bL_ops *ops); |
| 43 | void bL_cpufreq_unregister(struct cpufreq_arm_bL_ops *ops); | 38 | void bL_cpufreq_unregister(struct cpufreq_arm_bL_ops *ops); |
| 44 | 39 | ||
diff --git a/drivers/cpufreq/at32ap-cpufreq.c b/drivers/cpufreq/at32ap-cpufreq.c index 81d07527bde6..856ad80418ae 100644 --- a/drivers/cpufreq/at32ap-cpufreq.c +++ b/drivers/cpufreq/at32ap-cpufreq.c | |||
| @@ -37,27 +37,23 @@ static unsigned long loops_per_jiffy_ref; | |||
| 37 | 37 | ||
| 38 | static int at32_set_target(struct cpufreq_policy *policy, unsigned int index) | 38 | static int at32_set_target(struct cpufreq_policy *policy, unsigned int index) |
| 39 | { | 39 | { |
| 40 | struct cpufreq_freqs freqs; | 40 | unsigned int old_freq, new_freq; |
| 41 | 41 | ||
| 42 | freqs.old = at32_get_speed(0); | 42 | old_freq = at32_get_speed(0); |
| 43 | freqs.new = freq_table[index].frequency; | 43 | new_freq = freq_table[index].frequency; |
| 44 | 44 | ||
| 45 | if (!ref_freq) { | 45 | if (!ref_freq) { |
| 46 | ref_freq = freqs.old; | 46 | ref_freq = old_freq; |
| 47 | loops_per_jiffy_ref = boot_cpu_data.loops_per_jiffy; | 47 | loops_per_jiffy_ref = boot_cpu_data.loops_per_jiffy; |
| 48 | } | 48 | } |
| 49 | 49 | ||
| 50 | cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); | 50 | if (old_freq < new_freq) |
| 51 | if (freqs.old < freqs.new) | ||
| 52 | boot_cpu_data.loops_per_jiffy = cpufreq_scale( | 51 | boot_cpu_data.loops_per_jiffy = cpufreq_scale( |
| 53 | loops_per_jiffy_ref, ref_freq, freqs.new); | 52 | loops_per_jiffy_ref, ref_freq, new_freq); |
| 54 | clk_set_rate(cpuclk, freqs.new * 1000); | 53 | clk_set_rate(cpuclk, new_freq * 1000); |
| 55 | if (freqs.new < freqs.old) | 54 | if (new_freq < old_freq) |
| 56 | boot_cpu_data.loops_per_jiffy = cpufreq_scale( | 55 | boot_cpu_data.loops_per_jiffy = cpufreq_scale( |
| 57 | loops_per_jiffy_ref, ref_freq, freqs.new); | 56 | loops_per_jiffy_ref, ref_freq, new_freq); |
| 58 | cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); | ||
| 59 | |||
| 60 | pr_debug("cpufreq: set frequency %u Hz\n", freqs.new * 1000); | ||
| 61 | 57 | ||
| 62 | return 0; | 58 | return 0; |
| 63 | } | 59 | } |
diff --git a/drivers/cpufreq/blackfin-cpufreq.c b/drivers/cpufreq/blackfin-cpufreq.c index 12528b28d45d..e9e63fc9c2c9 100644 --- a/drivers/cpufreq/blackfin-cpufreq.c +++ b/drivers/cpufreq/blackfin-cpufreq.c | |||
| @@ -132,27 +132,23 @@ static int bfin_target(struct cpufreq_policy *policy, unsigned int index) | |||
| 132 | #ifndef CONFIG_BF60x | 132 | #ifndef CONFIG_BF60x |
| 133 | unsigned int plldiv; | 133 | unsigned int plldiv; |
| 134 | #endif | 134 | #endif |
| 135 | struct cpufreq_freqs freqs; | ||
| 136 | static unsigned long lpj_ref; | 135 | static unsigned long lpj_ref; |
| 137 | static unsigned int lpj_ref_freq; | 136 | static unsigned int lpj_ref_freq; |
| 137 | unsigned int old_freq, new_freq; | ||
| 138 | int ret = 0; | 138 | int ret = 0; |
| 139 | 139 | ||
| 140 | #if defined(CONFIG_CYCLES_CLOCKSOURCE) | 140 | #if defined(CONFIG_CYCLES_CLOCKSOURCE) |
| 141 | cycles_t cycles; | 141 | cycles_t cycles; |
| 142 | #endif | 142 | #endif |
| 143 | 143 | ||
| 144 | freqs.old = bfin_getfreq_khz(0); | 144 | old_freq = bfin_getfreq_khz(0); |
| 145 | freqs.new = bfin_freq_table[index].frequency; | 145 | new_freq = bfin_freq_table[index].frequency; |
| 146 | 146 | ||
| 147 | pr_debug("cpufreq: changing cclk to %lu; target = %u, oldfreq = %u\n", | ||
| 148 | freqs.new, freqs.new, freqs.old); | ||
| 149 | |||
| 150 | cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); | ||
| 151 | #ifndef CONFIG_BF60x | 147 | #ifndef CONFIG_BF60x |
| 152 | plldiv = (bfin_read_PLL_DIV() & SSEL) | dpm_state_table[index].csel; | 148 | plldiv = (bfin_read_PLL_DIV() & SSEL) | dpm_state_table[index].csel; |
| 153 | bfin_write_PLL_DIV(plldiv); | 149 | bfin_write_PLL_DIV(plldiv); |
| 154 | #else | 150 | #else |
| 155 | ret = cpu_set_cclk(policy->cpu, freqs.new * 1000); | 151 | ret = cpu_set_cclk(policy->cpu, new_freq * 1000); |
| 156 | if (ret != 0) { | 152 | if (ret != 0) { |
| 157 | WARN_ONCE(ret, "cpufreq set freq failed %d\n", ret); | 153 | WARN_ONCE(ret, "cpufreq set freq failed %d\n", ret); |
| 158 | return ret; | 154 | return ret; |
| @@ -168,17 +164,13 @@ static int bfin_target(struct cpufreq_policy *policy, unsigned int index) | |||
| 168 | #endif | 164 | #endif |
| 169 | if (!lpj_ref_freq) { | 165 | if (!lpj_ref_freq) { |
| 170 | lpj_ref = loops_per_jiffy; | 166 | lpj_ref = loops_per_jiffy; |
| 171 | lpj_ref_freq = freqs.old; | 167 | lpj_ref_freq = old_freq; |
| 172 | } | 168 | } |
| 173 | if (freqs.new != freqs.old) { | 169 | if (new_freq != old_freq) { |
| 174 | loops_per_jiffy = cpufreq_scale(lpj_ref, | 170 | loops_per_jiffy = cpufreq_scale(lpj_ref, |
| 175 | lpj_ref_freq, freqs.new); | 171 | lpj_ref_freq, new_freq); |
| 176 | } | 172 | } |
| 177 | 173 | ||
| 178 | /* TODO: just test case for cycles clock source, remove later */ | ||
| 179 | cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); | ||
| 180 | |||
| 181 | pr_debug("cpufreq: done\n"); | ||
| 182 | return ret; | 174 | return ret; |
| 183 | } | 175 | } |
| 184 | 176 | ||
diff --git a/drivers/cpufreq/cpufreq-cpu0.c b/drivers/cpufreq/cpufreq-cpu0.c index 4dbe7efd86e5..d4585ce2346c 100644 --- a/drivers/cpufreq/cpufreq-cpu0.c +++ b/drivers/cpufreq/cpufreq-cpu0.c | |||
| @@ -37,20 +37,19 @@ static unsigned int cpu0_get_speed(unsigned int cpu) | |||
| 37 | 37 | ||
| 38 | static int cpu0_set_target(struct cpufreq_policy *policy, unsigned int index) | 38 | static int cpu0_set_target(struct cpufreq_policy *policy, unsigned int index) |
| 39 | { | 39 | { |
| 40 | struct cpufreq_freqs freqs; | ||
| 41 | struct dev_pm_opp *opp; | 40 | struct dev_pm_opp *opp; |
| 42 | unsigned long volt = 0, volt_old = 0, tol = 0; | 41 | unsigned long volt = 0, volt_old = 0, tol = 0; |
| 42 | unsigned int old_freq, new_freq; | ||
| 43 | long freq_Hz, freq_exact; | 43 | long freq_Hz, freq_exact; |
| 44 | int ret; | 44 | int ret; |
| 45 | 45 | ||
| 46 | freq_Hz = clk_round_rate(cpu_clk, freq_table[index].frequency * 1000); | 46 | freq_Hz = clk_round_rate(cpu_clk, freq_table[index].frequency * 1000); |
| 47 | if (freq_Hz < 0) | 47 | if (freq_Hz < 0) |
| 48 | freq_Hz = freq_table[index].frequency * 1000; | 48 | freq_Hz = freq_table[index].frequency * 1000; |
| 49 | freq_exact = freq_Hz; | ||
| 50 | freqs.new = freq_Hz / 1000; | ||
| 51 | freqs.old = clk_get_rate(cpu_clk) / 1000; | ||
| 52 | 49 | ||
| 53 | cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); | 50 | freq_exact = freq_Hz; |
| 51 | new_freq = freq_Hz / 1000; | ||
| 52 | old_freq = clk_get_rate(cpu_clk) / 1000; | ||
| 54 | 53 | ||
| 55 | if (!IS_ERR(cpu_reg)) { | 54 | if (!IS_ERR(cpu_reg)) { |
| 56 | rcu_read_lock(); | 55 | rcu_read_lock(); |
| @@ -58,9 +57,7 @@ static int cpu0_set_target(struct cpufreq_policy *policy, unsigned int index) | |||
| 58 | if (IS_ERR(opp)) { | 57 | if (IS_ERR(opp)) { |
| 59 | rcu_read_unlock(); | 58 | rcu_read_unlock(); |
| 60 | pr_err("failed to find OPP for %ld\n", freq_Hz); | 59 | pr_err("failed to find OPP for %ld\n", freq_Hz); |
| 61 | freqs.new = freqs.old; | 60 | return PTR_ERR(opp); |
| 62 | ret = PTR_ERR(opp); | ||
| 63 | goto post_notify; | ||
| 64 | } | 61 | } |
| 65 | volt = dev_pm_opp_get_voltage(opp); | 62 | volt = dev_pm_opp_get_voltage(opp); |
| 66 | rcu_read_unlock(); | 63 | rcu_read_unlock(); |
| @@ -69,16 +66,15 @@ static int cpu0_set_target(struct cpufreq_policy *policy, unsigned int index) | |||
| 69 | } | 66 | } |
| 70 | 67 | ||
| 71 | pr_debug("%u MHz, %ld mV --> %u MHz, %ld mV\n", | 68 | pr_debug("%u MHz, %ld mV --> %u MHz, %ld mV\n", |
| 72 | freqs.old / 1000, volt_old ? volt_old / 1000 : -1, | 69 | old_freq / 1000, volt_old ? volt_old / 1000 : -1, |
| 73 | freqs.new / 1000, volt ? volt / 1000 : -1); | 70 | new_freq / 1000, volt ? volt / 1000 : -1); |
| 74 | 71 | ||
| 75 | /* scaling up? scale voltage before frequency */ | 72 | /* scaling up? scale voltage before frequency */ |
| 76 | if (!IS_ERR(cpu_reg) && freqs.new > freqs.old) { | 73 | if (!IS_ERR(cpu_reg) && new_freq > old_freq) { |
| 77 | ret = regulator_set_voltage_tol(cpu_reg, volt, tol); | 74 | ret = regulator_set_voltage_tol(cpu_reg, volt, tol); |
| 78 | if (ret) { | 75 | if (ret) { |
| 79 | pr_err("failed to scale voltage up: %d\n", ret); | 76 | pr_err("failed to scale voltage up: %d\n", ret); |
| 80 | freqs.new = freqs.old; | 77 | return ret; |
| 81 | goto post_notify; | ||
| 82 | } | 78 | } |
| 83 | } | 79 | } |
| 84 | 80 | ||
| @@ -87,23 +83,18 @@ static int cpu0_set_target(struct cpufreq_policy *policy, unsigned int index) | |||
| 87 | pr_err("failed to set clock rate: %d\n", ret); | 83 | pr_err("failed to set clock rate: %d\n", ret); |
| 88 | if (!IS_ERR(cpu_reg)) | 84 | if (!IS_ERR(cpu_reg)) |
| 89 | regulator_set_voltage_tol(cpu_reg, volt_old, tol); | 85 | regulator_set_voltage_tol(cpu_reg, volt_old, tol); |
| 90 | freqs.new = freqs.old; | 86 | return ret; |
| 91 | goto post_notify; | ||
| 92 | } | 87 | } |
| 93 | 88 | ||
| 94 | /* scaling down? scale voltage after frequency */ | 89 | /* scaling down? scale voltage after frequency */ |
| 95 | if (!IS_ERR(cpu_reg) && freqs.new < freqs.old) { | 90 | if (!IS_ERR(cpu_reg) && new_freq < old_freq) { |
| 96 | ret = regulator_set_voltage_tol(cpu_reg, volt, tol); | 91 | ret = regulator_set_voltage_tol(cpu_reg, volt, tol); |
| 97 | if (ret) { | 92 | if (ret) { |
| 98 | pr_err("failed to scale voltage down: %d\n", ret); | 93 | pr_err("failed to scale voltage down: %d\n", ret); |
| 99 | clk_set_rate(cpu_clk, freqs.old * 1000); | 94 | clk_set_rate(cpu_clk, old_freq * 1000); |
| 100 | freqs.new = freqs.old; | ||
| 101 | } | 95 | } |
| 102 | } | 96 | } |
| 103 | 97 | ||
| 104 | post_notify: | ||
| 105 | cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); | ||
| 106 | |||
| 107 | return ret; | 98 | return ret; |
| 108 | } | 99 | } |
| 109 | 100 | ||
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 6c9cbb9ebd1f..02d534da22dd 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c | |||
| @@ -1669,6 +1669,8 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy, | |||
| 1669 | retval = cpufreq_driver->target(policy, target_freq, relation); | 1669 | retval = cpufreq_driver->target(policy, target_freq, relation); |
| 1670 | else if (cpufreq_driver->target_index) { | 1670 | else if (cpufreq_driver->target_index) { |
| 1671 | struct cpufreq_frequency_table *freq_table; | 1671 | struct cpufreq_frequency_table *freq_table; |
| 1672 | struct cpufreq_freqs freqs; | ||
| 1673 | bool notify; | ||
| 1672 | int index; | 1674 | int index; |
| 1673 | 1675 | ||
| 1674 | freq_table = cpufreq_frequency_get_table(policy->cpu); | 1676 | freq_table = cpufreq_frequency_get_table(policy->cpu); |
| @@ -1684,10 +1686,42 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy, | |||
| 1684 | goto out; | 1686 | goto out; |
| 1685 | } | 1687 | } |
| 1686 | 1688 | ||
| 1687 | if (freq_table[index].frequency == policy->cur) | 1689 | if (freq_table[index].frequency == policy->cur) { |
| 1688 | retval = 0; | 1690 | retval = 0; |
| 1689 | else | 1691 | goto out; |
| 1690 | retval = cpufreq_driver->target_index(policy, index); | 1692 | } |
| 1693 | |||
| 1694 | notify = !(cpufreq_driver->flags & CPUFREQ_ASYNC_NOTIFICATION); | ||
| 1695 | |||
| 1696 | if (notify) { | ||
| 1697 | freqs.old = policy->cur; | ||
| 1698 | freqs.new = freq_table[index].frequency; | ||
| 1699 | freqs.flags = 0; | ||
| 1700 | |||
| 1701 | pr_debug("%s: cpu: %d, oldfreq: %u, new freq: %u\n", | ||
| 1702 | __func__, policy->cpu, freqs.old, | ||
| 1703 | freqs.new); | ||
| 1704 | |||
| 1705 | cpufreq_notify_transition(policy, &freqs, | ||
| 1706 | CPUFREQ_PRECHANGE); | ||
| 1707 | } | ||
| 1708 | |||
| 1709 | retval = cpufreq_driver->target_index(policy, index); | ||
| 1710 | if (retval) | ||
| 1711 | pr_err("%s: Failed to change cpu frequency: %d\n", | ||
| 1712 | __func__, retval); | ||
| 1713 | |||
| 1714 | if (notify) { | ||
| 1715 | /* | ||
| 1716 | * Notify with old freq in case we failed to change | ||
| 1717 | * frequency | ||
| 1718 | */ | ||
| 1719 | if (retval) | ||
| 1720 | freqs.new = freqs.old; | ||
| 1721 | |||
| 1722 | cpufreq_notify_transition(policy, &freqs, | ||
| 1723 | CPUFREQ_POSTCHANGE); | ||
| 1724 | } | ||
| 1691 | } | 1725 | } |
| 1692 | 1726 | ||
| 1693 | out: | 1727 | out: |
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c index 32f26f6e17c5..18d409189092 100644 --- a/drivers/cpufreq/cpufreq_ondemand.c +++ b/drivers/cpufreq/cpufreq_ondemand.c | |||
| @@ -168,7 +168,6 @@ static void od_check_cpu(int cpu, unsigned int load) | |||
| 168 | dbs_info->rate_mult = | 168 | dbs_info->rate_mult = |
| 169 | od_tuners->sampling_down_factor; | 169 | od_tuners->sampling_down_factor; |
| 170 | dbs_freq_increase(policy, policy->max); | 170 | dbs_freq_increase(policy, policy->max); |
| 171 | return; | ||
| 172 | } else { | 171 | } else { |
| 173 | /* Calculate the next frequency proportional to load */ | 172 | /* Calculate the next frequency proportional to load */ |
| 174 | unsigned int freq_next; | 173 | unsigned int freq_next; |
diff --git a/drivers/cpufreq/cris-artpec3-cpufreq.c b/drivers/cpufreq/cris-artpec3-cpufreq.c index 841857cf1562..86559040c54c 100644 --- a/drivers/cpufreq/cris-artpec3-cpufreq.c +++ b/drivers/cpufreq/cris-artpec3-cpufreq.c | |||
| @@ -29,15 +29,9 @@ static unsigned int cris_freq_get_cpu_frequency(unsigned int cpu) | |||
| 29 | 29 | ||
| 30 | static int cris_freq_target(struct cpufreq_policy *policy, unsigned int state) | 30 | static int cris_freq_target(struct cpufreq_policy *policy, unsigned int state) |
| 31 | { | 31 | { |
| 32 | struct cpufreq_freqs freqs; | ||
| 33 | reg_clkgen_rw_clk_ctrl clk_ctrl; | 32 | reg_clkgen_rw_clk_ctrl clk_ctrl; |
| 34 | clk_ctrl = REG_RD(clkgen, regi_clkgen, rw_clk_ctrl); | 33 | clk_ctrl = REG_RD(clkgen, regi_clkgen, rw_clk_ctrl); |
| 35 | 34 | ||
| 36 | freqs.old = cris_freq_get_cpu_frequency(policy->cpu); | ||
| 37 | freqs.new = cris_freq_table[state].frequency; | ||
| 38 | |||
| 39 | cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); | ||
| 40 | |||
| 41 | local_irq_disable(); | 35 | local_irq_disable(); |
| 42 | 36 | ||
| 43 | /* Even though we may be SMP they will share the same clock | 37 | /* Even though we may be SMP they will share the same clock |
| @@ -50,8 +44,6 @@ static int cris_freq_target(struct cpufreq_policy *policy, unsigned int state) | |||
| 50 | 44 | ||
| 51 | local_irq_enable(); | 45 | local_irq_enable(); |
| 52 | 46 | ||
| 53 | cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); | ||
| 54 | |||
| 55 | return 0; | 47 | return 0; |
| 56 | } | 48 | } |
| 57 | 49 | ||
diff --git a/drivers/cpufreq/cris-etraxfs-cpufreq.c b/drivers/cpufreq/cris-etraxfs-cpufreq.c index c58811abd961..26d940d40b1d 100644 --- a/drivers/cpufreq/cris-etraxfs-cpufreq.c +++ b/drivers/cpufreq/cris-etraxfs-cpufreq.c | |||
| @@ -29,15 +29,9 @@ static unsigned int cris_freq_get_cpu_frequency(unsigned int cpu) | |||
| 29 | 29 | ||
| 30 | static int cris_freq_target(struct cpufreq_policy *policy, unsigned int state) | 30 | static int cris_freq_target(struct cpufreq_policy *policy, unsigned int state) |
| 31 | { | 31 | { |
| 32 | struct cpufreq_freqs freqs; | ||
| 33 | reg_config_rw_clk_ctrl clk_ctrl; | 32 | reg_config_rw_clk_ctrl clk_ctrl; |
| 34 | clk_ctrl = REG_RD(config, regi_config, rw_clk_ctrl); | 33 | clk_ctrl = REG_RD(config, regi_config, rw_clk_ctrl); |
| 35 | 34 | ||
| 36 | freqs.old = cris_freq_get_cpu_frequency(policy->cpu); | ||
| 37 | freqs.new = cris_freq_table[state].frequency; | ||
| 38 | |||
| 39 | cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); | ||
| 40 | |||
| 41 | local_irq_disable(); | 35 | local_irq_disable(); |
| 42 | 36 | ||
| 43 | /* Even though we may be SMP they will share the same clock | 37 | /* Even though we may be SMP they will share the same clock |
| @@ -50,8 +44,6 @@ static int cris_freq_target(struct cpufreq_policy *policy, unsigned int state) | |||
| 50 | 44 | ||
| 51 | local_irq_enable(); | 45 | local_irq_enable(); |
| 52 | 46 | ||
| 53 | cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); | ||
| 54 | |||
| 55 | return 0; | 47 | return 0; |
| 56 | } | 48 | } |
| 57 | 49 | ||
diff --git a/drivers/cpufreq/davinci-cpufreq.c b/drivers/cpufreq/davinci-cpufreq.c index 1f5d8a569c77..5e8a854381b7 100644 --- a/drivers/cpufreq/davinci-cpufreq.c +++ b/drivers/cpufreq/davinci-cpufreq.c | |||
| @@ -68,46 +68,36 @@ static unsigned int davinci_getspeed(unsigned int cpu) | |||
| 68 | 68 | ||
| 69 | static int davinci_target(struct cpufreq_policy *policy, unsigned int idx) | 69 | static int davinci_target(struct cpufreq_policy *policy, unsigned int idx) |
| 70 | { | 70 | { |
| 71 | int ret = 0; | ||
| 72 | struct cpufreq_freqs freqs; | ||
| 73 | struct davinci_cpufreq_config *pdata = cpufreq.dev->platform_data; | 71 | struct davinci_cpufreq_config *pdata = cpufreq.dev->platform_data; |
| 74 | struct clk *armclk = cpufreq.armclk; | 72 | struct clk *armclk = cpufreq.armclk; |
| 73 | unsigned int old_freq, new_freq; | ||
| 74 | int ret = 0; | ||
| 75 | 75 | ||
| 76 | freqs.old = davinci_getspeed(0); | 76 | old_freq = davinci_getspeed(0); |
| 77 | freqs.new = pdata->freq_table[idx].frequency; | 77 | new_freq = pdata->freq_table[idx].frequency; |
| 78 | |||
| 79 | dev_dbg(cpufreq.dev, "transition: %u --> %u\n", freqs.old, freqs.new); | ||
| 80 | |||
| 81 | cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); | ||
| 82 | 78 | ||
| 83 | /* if moving to higher frequency, up the voltage beforehand */ | 79 | /* if moving to higher frequency, up the voltage beforehand */ |
| 84 | if (pdata->set_voltage && freqs.new > freqs.old) { | 80 | if (pdata->set_voltage && new_freq > old_freq) { |
| 85 | ret = pdata->set_voltage(idx); | 81 | ret = pdata->set_voltage(idx); |
| 86 | if (ret) | 82 | if (ret) |
| 87 | goto out; | 83 | return ret; |
| 88 | } | 84 | } |
| 89 | 85 | ||
| 90 | ret = clk_set_rate(armclk, idx); | 86 | ret = clk_set_rate(armclk, idx); |
| 91 | if (ret) | 87 | if (ret) |
| 92 | goto out; | 88 | return ret; |
| 93 | 89 | ||
| 94 | if (cpufreq.asyncclk) { | 90 | if (cpufreq.asyncclk) { |
| 95 | ret = clk_set_rate(cpufreq.asyncclk, cpufreq.asyncrate); | 91 | ret = clk_set_rate(cpufreq.asyncclk, cpufreq.asyncrate); |
| 96 | if (ret) | 92 | if (ret) |
| 97 | goto out; | 93 | return ret; |
| 98 | } | 94 | } |
| 99 | 95 | ||
| 100 | /* if moving to lower freq, lower the voltage after lowering freq */ | 96 | /* if moving to lower freq, lower the voltage after lowering freq */ |
| 101 | if (pdata->set_voltage && freqs.new < freqs.old) | 97 | if (pdata->set_voltage && new_freq < old_freq) |
| 102 | pdata->set_voltage(idx); | 98 | pdata->set_voltage(idx); |
| 103 | 99 | ||
| 104 | out: | 100 | return 0; |
| 105 | if (ret) | ||
| 106 | freqs.new = freqs.old; | ||
| 107 | |||
| 108 | cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); | ||
| 109 | |||
| 110 | return ret; | ||
| 111 | } | 101 | } |
| 112 | 102 | ||
| 113 | static int davinci_cpu_init(struct cpufreq_policy *policy) | 103 | static int davinci_cpu_init(struct cpufreq_policy *policy) |
diff --git a/drivers/cpufreq/dbx500-cpufreq.c b/drivers/cpufreq/dbx500-cpufreq.c index 238b16976be1..0e67ab96321a 100644 --- a/drivers/cpufreq/dbx500-cpufreq.c +++ b/drivers/cpufreq/dbx500-cpufreq.c | |||
| @@ -22,28 +22,8 @@ static struct clk *armss_clk; | |||
| 22 | static int dbx500_cpufreq_target(struct cpufreq_policy *policy, | 22 | static int dbx500_cpufreq_target(struct cpufreq_policy *policy, |
| 23 | unsigned int index) | 23 | unsigned int index) |
| 24 | { | 24 | { |
| 25 | struct cpufreq_freqs freqs; | ||
| 26 | int ret; | ||
| 27 | |||
| 28 | freqs.old = policy->cur; | ||
| 29 | freqs.new = freq_table[index].frequency; | ||
| 30 | |||
| 31 | /* pre-change notification */ | ||
| 32 | cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); | ||
| 33 | |||
| 34 | /* update armss clk frequency */ | 25 | /* update armss clk frequency */ |
| 35 | ret = clk_set_rate(armss_clk, freqs.new * 1000); | 26 | return clk_set_rate(armss_clk, freq_table[index].frequency * 1000); |
| 36 | |||
| 37 | if (ret) { | ||
| 38 | pr_err("dbx500-cpufreq: Failed to set armss_clk to %d Hz: error %d\n", | ||
| 39 | freqs.new * 1000, ret); | ||
| 40 | freqs.new = freqs.old; | ||
| 41 | } | ||
| 42 | |||
| 43 | /* post change notification */ | ||
| 44 | cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); | ||
| 45 | |||
| 46 | return ret; | ||
| 47 | } | 27 | } |
| 48 | 28 | ||
| 49 | static unsigned int dbx500_cpufreq_getspeed(unsigned int cpu) | 29 | static unsigned int dbx500_cpufreq_getspeed(unsigned int cpu) |
diff --git a/drivers/cpufreq/e_powersaver.c b/drivers/cpufreq/e_powersaver.c index b39c4ef60a7a..9012b8bb6b64 100644 --- a/drivers/cpufreq/e_powersaver.c +++ b/drivers/cpufreq/e_powersaver.c | |||
| @@ -107,15 +107,9 @@ static int eps_set_state(struct eps_cpu_data *centaur, | |||
| 107 | struct cpufreq_policy *policy, | 107 | struct cpufreq_policy *policy, |
| 108 | u32 dest_state) | 108 | u32 dest_state) |
| 109 | { | 109 | { |
| 110 | struct cpufreq_freqs freqs; | ||
| 111 | u32 lo, hi; | 110 | u32 lo, hi; |
| 112 | int err = 0; | ||
| 113 | int i; | 111 | int i; |
| 114 | 112 | ||
| 115 | freqs.old = eps_get(policy->cpu); | ||
| 116 | freqs.new = centaur->fsb * ((dest_state >> 8) & 0xff); | ||
| 117 | cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); | ||
| 118 | |||
| 119 | /* Wait while CPU is busy */ | 113 | /* Wait while CPU is busy */ |
| 120 | rdmsr(MSR_IA32_PERF_STATUS, lo, hi); | 114 | rdmsr(MSR_IA32_PERF_STATUS, lo, hi); |
| 121 | i = 0; | 115 | i = 0; |
| @@ -124,8 +118,7 @@ static int eps_set_state(struct eps_cpu_data *centaur, | |||
| 124 | rdmsr(MSR_IA32_PERF_STATUS, lo, hi); | 118 | rdmsr(MSR_IA32_PERF_STATUS, lo, hi); |
| 125 | i++; | 119 | i++; |
| 126 | if (unlikely(i > 64)) { | 120 | if (unlikely(i > 64)) { |
| 127 | err = -ENODEV; | 121 | return -ENODEV; |
| 128 | goto postchange; | ||
| 129 | } | 122 | } |
| 130 | } | 123 | } |
| 131 | /* Set new multiplier and voltage */ | 124 | /* Set new multiplier and voltage */ |
| @@ -137,16 +130,10 @@ static int eps_set_state(struct eps_cpu_data *centaur, | |||
| 137 | rdmsr(MSR_IA32_PERF_STATUS, lo, hi); | 130 | rdmsr(MSR_IA32_PERF_STATUS, lo, hi); |
| 138 | i++; | 131 | i++; |
| 139 | if (unlikely(i > 64)) { | 132 | if (unlikely(i > 64)) { |
| 140 | err = -ENODEV; | 133 | return -ENODEV; |
| 141 | goto postchange; | ||
| 142 | } | 134 | } |
| 143 | } while (lo & ((1 << 16) | (1 << 17))); | 135 | } while (lo & ((1 << 16) | (1 << 17))); |
| 144 | 136 | ||
| 145 | /* Return current frequency */ | ||
| 146 | postchange: | ||
| 147 | rdmsr(MSR_IA32_PERF_STATUS, lo, hi); | ||
| 148 | freqs.new = centaur->fsb * ((lo >> 8) & 0xff); | ||
| 149 | |||
| 150 | #ifdef DEBUG | 137 | #ifdef DEBUG |
| 151 | { | 138 | { |
| 152 | u8 current_multiplier, current_voltage; | 139 | u8 current_multiplier, current_voltage; |
| @@ -161,11 +148,7 @@ postchange: | |||
| 161 | current_multiplier); | 148 | current_multiplier); |
| 162 | } | 149 | } |
| 163 | #endif | 150 | #endif |
| 164 | if (err) | 151 | return 0; |
| 165 | freqs.new = freqs.old; | ||
| 166 | |||
| 167 | cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); | ||
| 168 | return err; | ||
| 169 | } | 152 | } |
| 170 | 153 | ||
| 171 | static int eps_target(struct cpufreq_policy *policy, unsigned int index) | 154 | static int eps_target(struct cpufreq_policy *policy, unsigned int index) |
diff --git a/drivers/cpufreq/elanfreq.c b/drivers/cpufreq/elanfreq.c index 4ab41539514f..de08acff5101 100644 --- a/drivers/cpufreq/elanfreq.c +++ b/drivers/cpufreq/elanfreq.c | |||
| @@ -108,17 +108,6 @@ static unsigned int elanfreq_get_cpu_frequency(unsigned int cpu) | |||
| 108 | static int elanfreq_target(struct cpufreq_policy *policy, | 108 | static int elanfreq_target(struct cpufreq_policy *policy, |
| 109 | unsigned int state) | 109 | unsigned int state) |
| 110 | { | 110 | { |
| 111 | struct cpufreq_freqs freqs; | ||
| 112 | |||
| 113 | freqs.old = elanfreq_get_cpu_frequency(0); | ||
| 114 | freqs.new = elan_multiplier[state].clock; | ||
| 115 | |||
| 116 | cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); | ||
| 117 | |||
| 118 | printk(KERN_INFO "elanfreq: attempting to set frequency to %i kHz\n", | ||
| 119 | elan_multiplier[state].clock); | ||
| 120 | |||
| 121 | |||
| 122 | /* | 111 | /* |
| 123 | * Access to the Elan's internal registers is indexed via | 112 | * Access to the Elan's internal registers is indexed via |
| 124 | * 0x22: Chip Setup & Control Register Index Register (CSCI) | 113 | * 0x22: Chip Setup & Control Register Index Register (CSCI) |
| @@ -149,8 +138,6 @@ static int elanfreq_target(struct cpufreq_policy *policy, | |||
| 149 | udelay(10000); | 138 | udelay(10000); |
| 150 | local_irq_enable(); | 139 | local_irq_enable(); |
| 151 | 140 | ||
| 152 | cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); | ||
| 153 | |||
| 154 | return 0; | 141 | return 0; |
| 155 | } | 142 | } |
| 156 | /* | 143 | /* |
diff --git a/drivers/cpufreq/exynos-cpufreq.c b/drivers/cpufreq/exynos-cpufreq.c index 9982fcb82257..7b6dc06b1bd4 100644 --- a/drivers/cpufreq/exynos-cpufreq.c +++ b/drivers/cpufreq/exynos-cpufreq.c | |||
| @@ -25,7 +25,6 @@ | |||
| 25 | static struct exynos_dvfs_info *exynos_info; | 25 | static struct exynos_dvfs_info *exynos_info; |
| 26 | 26 | ||
| 27 | static struct regulator *arm_regulator; | 27 | static struct regulator *arm_regulator; |
| 28 | static struct cpufreq_freqs freqs; | ||
| 29 | 28 | ||
| 30 | static unsigned int locking_frequency; | 29 | static unsigned int locking_frequency; |
| 31 | static bool frequency_locked; | 30 | static bool frequency_locked; |
| @@ -59,18 +58,18 @@ static int exynos_cpufreq_scale(unsigned int target_freq) | |||
| 59 | struct cpufreq_policy *policy = cpufreq_cpu_get(0); | 58 | struct cpufreq_policy *policy = cpufreq_cpu_get(0); |
| 60 | unsigned int arm_volt, safe_arm_volt = 0; | 59 | unsigned int arm_volt, safe_arm_volt = 0; |
| 61 | unsigned int mpll_freq_khz = exynos_info->mpll_freq_khz; | 60 | unsigned int mpll_freq_khz = exynos_info->mpll_freq_khz; |
| 61 | unsigned int old_freq; | ||
| 62 | int index, old_index; | 62 | int index, old_index; |
| 63 | int ret = 0; | 63 | int ret = 0; |
| 64 | 64 | ||
| 65 | freqs.old = policy->cur; | 65 | old_freq = policy->cur; |
| 66 | freqs.new = target_freq; | ||
| 67 | 66 | ||
| 68 | /* | 67 | /* |
| 69 | * The policy max have been changed so that we cannot get proper | 68 | * The policy max have been changed so that we cannot get proper |
| 70 | * old_index with cpufreq_frequency_table_target(). Thus, ignore | 69 | * old_index with cpufreq_frequency_table_target(). Thus, ignore |
| 71 | * policy and get the index from the raw freqeuncy table. | 70 | * policy and get the index from the raw freqeuncy table. |
| 72 | */ | 71 | */ |
| 73 | old_index = exynos_cpufreq_get_index(freqs.old); | 72 | old_index = exynos_cpufreq_get_index(old_freq); |
| 74 | if (old_index < 0) { | 73 | if (old_index < 0) { |
| 75 | ret = old_index; | 74 | ret = old_index; |
| 76 | goto out; | 75 | goto out; |
| @@ -95,17 +94,14 @@ static int exynos_cpufreq_scale(unsigned int target_freq) | |||
| 95 | } | 94 | } |
| 96 | arm_volt = volt_table[index]; | 95 | arm_volt = volt_table[index]; |
| 97 | 96 | ||
| 98 | cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); | ||
| 99 | |||
| 100 | /* When the new frequency is higher than current frequency */ | 97 | /* When the new frequency is higher than current frequency */ |
| 101 | if ((freqs.new > freqs.old) && !safe_arm_volt) { | 98 | if ((target_freq > old_freq) && !safe_arm_volt) { |
| 102 | /* Firstly, voltage up to increase frequency */ | 99 | /* Firstly, voltage up to increase frequency */ |
| 103 | ret = regulator_set_voltage(arm_regulator, arm_volt, arm_volt); | 100 | ret = regulator_set_voltage(arm_regulator, arm_volt, arm_volt); |
| 104 | if (ret) { | 101 | if (ret) { |
| 105 | pr_err("%s: failed to set cpu voltage to %d\n", | 102 | pr_err("%s: failed to set cpu voltage to %d\n", |
| 106 | __func__, arm_volt); | 103 | __func__, arm_volt); |
| 107 | freqs.new = freqs.old; | 104 | return ret; |
| 108 | goto post_notify; | ||
| 109 | } | 105 | } |
| 110 | } | 106 | } |
| 111 | 107 | ||
| @@ -115,22 +111,15 @@ static int exynos_cpufreq_scale(unsigned int target_freq) | |||
| 115 | if (ret) { | 111 | if (ret) { |
| 116 | pr_err("%s: failed to set cpu voltage to %d\n", | 112 | pr_err("%s: failed to set cpu voltage to %d\n", |
| 117 | __func__, safe_arm_volt); | 113 | __func__, safe_arm_volt); |
| 118 | freqs.new = freqs.old; | 114 | return ret; |
| 119 | goto post_notify; | ||
| 120 | } | 115 | } |
| 121 | } | 116 | } |
| 122 | 117 | ||
| 123 | exynos_info->set_freq(old_index, index); | 118 | exynos_info->set_freq(old_index, index); |
| 124 | 119 | ||
| 125 | post_notify: | ||
| 126 | cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); | ||
| 127 | |||
| 128 | if (ret) | ||
| 129 | goto out; | ||
| 130 | |||
| 131 | /* When the new frequency is lower than current frequency */ | 120 | /* When the new frequency is lower than current frequency */ |
| 132 | if ((freqs.new < freqs.old) || | 121 | if ((target_freq < old_freq) || |
| 133 | ((freqs.new > freqs.old) && safe_arm_volt)) { | 122 | ((target_freq > old_freq) && safe_arm_volt)) { |
| 134 | /* down the voltage after frequency change */ | 123 | /* down the voltage after frequency change */ |
| 135 | ret = regulator_set_voltage(arm_regulator, arm_volt, | 124 | ret = regulator_set_voltage(arm_regulator, arm_volt, |
| 136 | arm_volt); | 125 | arm_volt); |
| @@ -142,7 +131,6 @@ post_notify: | |||
| 142 | } | 131 | } |
| 143 | 132 | ||
| 144 | out: | 133 | out: |
| 145 | |||
| 146 | cpufreq_cpu_put(policy); | 134 | cpufreq_cpu_put(policy); |
| 147 | 135 | ||
| 148 | return ret; | 136 | return ret; |
diff --git a/drivers/cpufreq/exynos5440-cpufreq.c b/drivers/cpufreq/exynos5440-cpufreq.c index 1bf9b060d522..76bef8b078cb 100644 --- a/drivers/cpufreq/exynos5440-cpufreq.c +++ b/drivers/cpufreq/exynos5440-cpufreq.c | |||
| @@ -312,7 +312,7 @@ static int exynos_cpufreq_cpu_init(struct cpufreq_policy *policy) | |||
| 312 | } | 312 | } |
| 313 | 313 | ||
| 314 | static struct cpufreq_driver exynos_driver = { | 314 | static struct cpufreq_driver exynos_driver = { |
| 315 | .flags = CPUFREQ_STICKY, | 315 | .flags = CPUFREQ_STICKY | CPUFREQ_ASYNC_NOTIFICATION, |
| 316 | .verify = cpufreq_generic_frequency_table_verify, | 316 | .verify = cpufreq_generic_frequency_table_verify, |
| 317 | .target_index = exynos_target, | 317 | .target_index = exynos_target, |
| 318 | .get = exynos_getspeed, | 318 | .get = exynos_getspeed, |
diff --git a/drivers/cpufreq/ia64-acpi-cpufreq.c b/drivers/cpufreq/ia64-acpi-cpufreq.c index 4695fa22406a..53c6ac637e10 100644 --- a/drivers/cpufreq/ia64-acpi-cpufreq.c +++ b/drivers/cpufreq/ia64-acpi-cpufreq.c | |||
| @@ -141,7 +141,6 @@ processor_set_freq ( | |||
| 141 | { | 141 | { |
| 142 | int ret = 0; | 142 | int ret = 0; |
| 143 | u32 value = 0; | 143 | u32 value = 0; |
| 144 | struct cpufreq_freqs cpufreq_freqs; | ||
| 145 | cpumask_t saved_mask; | 144 | cpumask_t saved_mask; |
| 146 | int retval; | 145 | int retval; |
| 147 | 146 | ||
| @@ -168,13 +167,6 @@ processor_set_freq ( | |||
| 168 | pr_debug("Transitioning from P%d to P%d\n", | 167 | pr_debug("Transitioning from P%d to P%d\n", |
| 169 | data->acpi_data.state, state); | 168 | data->acpi_data.state, state); |
| 170 | 169 | ||
| 171 | /* cpufreq frequency struct */ | ||
| 172 | cpufreq_freqs.old = data->freq_table[data->acpi_data.state].frequency; | ||
| 173 | cpufreq_freqs.new = data->freq_table[state].frequency; | ||
| 174 | |||
| 175 | /* notify cpufreq */ | ||
| 176 | cpufreq_notify_transition(policy, &cpufreq_freqs, CPUFREQ_PRECHANGE); | ||
| 177 | |||
| 178 | /* | 170 | /* |
| 179 | * First we write the target state's 'control' value to the | 171 | * First we write the target state's 'control' value to the |
| 180 | * control_register. | 172 | * control_register. |
| @@ -186,22 +178,11 @@ processor_set_freq ( | |||
| 186 | 178 | ||
| 187 | ret = processor_set_pstate(value); | 179 | ret = processor_set_pstate(value); |
| 188 | if (ret) { | 180 | if (ret) { |
| 189 | unsigned int tmp = cpufreq_freqs.new; | ||
| 190 | cpufreq_notify_transition(policy, &cpufreq_freqs, | ||
| 191 | CPUFREQ_POSTCHANGE); | ||
| 192 | cpufreq_freqs.new = cpufreq_freqs.old; | ||
| 193 | cpufreq_freqs.old = tmp; | ||
| 194 | cpufreq_notify_transition(policy, &cpufreq_freqs, | ||
| 195 | CPUFREQ_PRECHANGE); | ||
| 196 | cpufreq_notify_transition(policy, &cpufreq_freqs, | ||
| 197 | CPUFREQ_POSTCHANGE); | ||
| 198 | printk(KERN_WARNING "Transition failed with error %d\n", ret); | 181 | printk(KERN_WARNING "Transition failed with error %d\n", ret); |
| 199 | retval = -ENODEV; | 182 | retval = -ENODEV; |
| 200 | goto migrate_end; | 183 | goto migrate_end; |
| 201 | } | 184 | } |
| 202 | 185 | ||
| 203 | cpufreq_notify_transition(policy, &cpufreq_freqs, CPUFREQ_POSTCHANGE); | ||
| 204 | |||
| 205 | data->acpi_data.state = state; | 186 | data->acpi_data.state = state; |
| 206 | 187 | ||
| 207 | retval = 0; | 188 | retval = 0; |
diff --git a/drivers/cpufreq/imx6q-cpufreq.c b/drivers/cpufreq/imx6q-cpufreq.c index 07af3b0de069..4b3f18e5f36b 100644 --- a/drivers/cpufreq/imx6q-cpufreq.c +++ b/drivers/cpufreq/imx6q-cpufreq.c | |||
| @@ -42,14 +42,14 @@ static unsigned int imx6q_get_speed(unsigned int cpu) | |||
| 42 | 42 | ||
| 43 | static int imx6q_set_target(struct cpufreq_policy *policy, unsigned int index) | 43 | static int imx6q_set_target(struct cpufreq_policy *policy, unsigned int index) |
| 44 | { | 44 | { |
| 45 | struct cpufreq_freqs freqs; | ||
| 46 | struct dev_pm_opp *opp; | 45 | struct dev_pm_opp *opp; |
| 47 | unsigned long freq_hz, volt, volt_old; | 46 | unsigned long freq_hz, volt, volt_old; |
| 47 | unsigned int old_freq, new_freq; | ||
| 48 | int ret; | 48 | int ret; |
| 49 | 49 | ||
| 50 | freqs.new = freq_table[index].frequency; | 50 | new_freq = freq_table[index].frequency; |
| 51 | freq_hz = freqs.new * 1000; | 51 | freq_hz = new_freq * 1000; |
| 52 | freqs.old = clk_get_rate(arm_clk) / 1000; | 52 | old_freq = clk_get_rate(arm_clk) / 1000; |
| 53 | 53 | ||
| 54 | rcu_read_lock(); | 54 | rcu_read_lock(); |
| 55 | opp = dev_pm_opp_find_freq_ceil(cpu_dev, &freq_hz); | 55 | opp = dev_pm_opp_find_freq_ceil(cpu_dev, &freq_hz); |
| @@ -64,26 +64,23 @@ static int imx6q_set_target(struct cpufreq_policy *policy, unsigned int index) | |||
| 64 | volt_old = regulator_get_voltage(arm_reg); | 64 | volt_old = regulator_get_voltage(arm_reg); |
| 65 | 65 | ||
| 66 | dev_dbg(cpu_dev, "%u MHz, %ld mV --> %u MHz, %ld mV\n", | 66 | dev_dbg(cpu_dev, "%u MHz, %ld mV --> %u MHz, %ld mV\n", |
| 67 | freqs.old / 1000, volt_old / 1000, | 67 | old_freq / 1000, volt_old / 1000, |
| 68 | freqs.new / 1000, volt / 1000); | 68 | new_freq / 1000, volt / 1000); |
| 69 | |||
| 70 | cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); | ||
| 71 | 69 | ||
| 72 | /* scaling up? scale voltage before frequency */ | 70 | /* scaling up? scale voltage before frequency */ |
| 73 | if (freqs.new > freqs.old) { | 71 | if (new_freq > old_freq) { |
| 74 | ret = regulator_set_voltage_tol(arm_reg, volt, 0); | 72 | ret = regulator_set_voltage_tol(arm_reg, volt, 0); |
| 75 | if (ret) { | 73 | if (ret) { |
| 76 | dev_err(cpu_dev, | 74 | dev_err(cpu_dev, |
| 77 | "failed to scale vddarm up: %d\n", ret); | 75 | "failed to scale vddarm up: %d\n", ret); |
| 78 | freqs.new = freqs.old; | 76 | return ret; |
| 79 | goto post_notify; | ||
| 80 | } | 77 | } |
| 81 | 78 | ||
| 82 | /* | 79 | /* |
| 83 | * Need to increase vddpu and vddsoc for safety | 80 | * Need to increase vddpu and vddsoc for safety |
| 84 | * if we are about to run at 1.2 GHz. | 81 | * if we are about to run at 1.2 GHz. |
| 85 | */ | 82 | */ |
| 86 | if (freqs.new == FREQ_1P2_GHZ / 1000) { | 83 | if (new_freq == FREQ_1P2_GHZ / 1000) { |
| 87 | regulator_set_voltage_tol(pu_reg, | 84 | regulator_set_voltage_tol(pu_reg, |
| 88 | PU_SOC_VOLTAGE_HIGH, 0); | 85 | PU_SOC_VOLTAGE_HIGH, 0); |
| 89 | regulator_set_voltage_tol(soc_reg, | 86 | regulator_set_voltage_tol(soc_reg, |
| @@ -103,21 +100,20 @@ static int imx6q_set_target(struct cpufreq_policy *policy, unsigned int index) | |||
| 103 | clk_set_parent(step_clk, pll2_pfd2_396m_clk); | 100 | clk_set_parent(step_clk, pll2_pfd2_396m_clk); |
| 104 | clk_set_parent(pll1_sw_clk, step_clk); | 101 | clk_set_parent(pll1_sw_clk, step_clk); |
| 105 | if (freq_hz > clk_get_rate(pll2_pfd2_396m_clk)) { | 102 | if (freq_hz > clk_get_rate(pll2_pfd2_396m_clk)) { |
| 106 | clk_set_rate(pll1_sys_clk, freqs.new * 1000); | 103 | clk_set_rate(pll1_sys_clk, new_freq * 1000); |
| 107 | clk_set_parent(pll1_sw_clk, pll1_sys_clk); | 104 | clk_set_parent(pll1_sw_clk, pll1_sys_clk); |
| 108 | } | 105 | } |
| 109 | 106 | ||
| 110 | /* Ensure the arm clock divider is what we expect */ | 107 | /* Ensure the arm clock divider is what we expect */ |
| 111 | ret = clk_set_rate(arm_clk, freqs.new * 1000); | 108 | ret = clk_set_rate(arm_clk, new_freq * 1000); |
| 112 | if (ret) { | 109 | if (ret) { |
| 113 | dev_err(cpu_dev, "failed to set clock rate: %d\n", ret); | 110 | dev_err(cpu_dev, "failed to set clock rate: %d\n", ret); |
| 114 | regulator_set_voltage_tol(arm_reg, volt_old, 0); | 111 | regulator_set_voltage_tol(arm_reg, volt_old, 0); |
| 115 | freqs.new = freqs.old; | 112 | return ret; |
| 116 | goto post_notify; | ||
| 117 | } | 113 | } |
| 118 | 114 | ||
| 119 | /* scaling down? scale voltage after frequency */ | 115 | /* scaling down? scale voltage after frequency */ |
| 120 | if (freqs.new < freqs.old) { | 116 | if (new_freq < old_freq) { |
| 121 | ret = regulator_set_voltage_tol(arm_reg, volt, 0); | 117 | ret = regulator_set_voltage_tol(arm_reg, volt, 0); |
| 122 | if (ret) { | 118 | if (ret) { |
| 123 | dev_warn(cpu_dev, | 119 | dev_warn(cpu_dev, |
| @@ -125,7 +121,7 @@ static int imx6q_set_target(struct cpufreq_policy *policy, unsigned int index) | |||
| 125 | ret = 0; | 121 | ret = 0; |
| 126 | } | 122 | } |
| 127 | 123 | ||
| 128 | if (freqs.old == FREQ_1P2_GHZ / 1000) { | 124 | if (old_freq == FREQ_1P2_GHZ / 1000) { |
| 129 | regulator_set_voltage_tol(pu_reg, | 125 | regulator_set_voltage_tol(pu_reg, |
| 130 | PU_SOC_VOLTAGE_NORMAL, 0); | 126 | PU_SOC_VOLTAGE_NORMAL, 0); |
| 131 | regulator_set_voltage_tol(soc_reg, | 127 | regulator_set_voltage_tol(soc_reg, |
| @@ -133,10 +129,7 @@ static int imx6q_set_target(struct cpufreq_policy *policy, unsigned int index) | |||
| 133 | } | 129 | } |
| 134 | } | 130 | } |
| 135 | 131 | ||
| 136 | post_notify: | 132 | return 0; |
| 137 | cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); | ||
| 138 | |||
| 139 | return ret; | ||
| 140 | } | 133 | } |
| 141 | 134 | ||
| 142 | static int imx6q_cpufreq_init(struct cpufreq_policy *policy) | 135 | static int imx6q_cpufreq_init(struct cpufreq_policy *policy) |
diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index 89925513fea5..5f1cbae36961 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c | |||
| @@ -25,6 +25,7 @@ | |||
| 25 | #include <linux/types.h> | 25 | #include <linux/types.h> |
| 26 | #include <linux/fs.h> | 26 | #include <linux/fs.h> |
| 27 | #include <linux/debugfs.h> | 27 | #include <linux/debugfs.h> |
| 28 | #include <linux/acpi.h> | ||
| 28 | #include <trace/events/power.h> | 29 | #include <trace/events/power.h> |
| 29 | 30 | ||
| 30 | #include <asm/div64.h> | 31 | #include <asm/div64.h> |
| @@ -759,7 +760,7 @@ static int intel_pstate_msrs_not_valid(void) | |||
| 759 | return 0; | 760 | return 0; |
| 760 | } | 761 | } |
| 761 | 762 | ||
| 762 | void copy_pid_params(struct pstate_adjust_policy *policy) | 763 | static void copy_pid_params(struct pstate_adjust_policy *policy) |
| 763 | { | 764 | { |
| 764 | pid_params.sample_rate_ms = policy->sample_rate_ms; | 765 | pid_params.sample_rate_ms = policy->sample_rate_ms; |
| 765 | pid_params.p_gain_pct = policy->p_gain_pct; | 766 | pid_params.p_gain_pct = policy->p_gain_pct; |
| @@ -769,7 +770,7 @@ void copy_pid_params(struct pstate_adjust_policy *policy) | |||
| 769 | pid_params.setpoint = policy->setpoint; | 770 | pid_params.setpoint = policy->setpoint; |
| 770 | } | 771 | } |
| 771 | 772 | ||
| 772 | void copy_cpu_funcs(struct pstate_funcs *funcs) | 773 | static void copy_cpu_funcs(struct pstate_funcs *funcs) |
| 773 | { | 774 | { |
| 774 | pstate_funcs.get_max = funcs->get_max; | 775 | pstate_funcs.get_max = funcs->get_max; |
| 775 | pstate_funcs.get_min = funcs->get_min; | 776 | pstate_funcs.get_min = funcs->get_min; |
| @@ -777,6 +778,72 @@ void copy_cpu_funcs(struct pstate_funcs *funcs) | |||
| 777 | pstate_funcs.set = funcs->set; | 778 | pstate_funcs.set = funcs->set; |
| 778 | } | 779 | } |
| 779 | 780 | ||
| 781 | #if IS_ENABLED(CONFIG_ACPI) | ||
| 782 | #include <acpi/processor.h> | ||
| 783 | |||
| 784 | static bool intel_pstate_no_acpi_pss(void) | ||
| 785 | { | ||
| 786 | int i; | ||
| 787 | |||
| 788 | for_each_possible_cpu(i) { | ||
| 789 | acpi_status status; | ||
| 790 | union acpi_object *pss; | ||
| 791 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
| 792 | struct acpi_processor *pr = per_cpu(processors, i); | ||
| 793 | |||
| 794 | if (!pr) | ||
| 795 | continue; | ||
| 796 | |||
| 797 | status = acpi_evaluate_object(pr->handle, "_PSS", NULL, &buffer); | ||
| 798 | if (ACPI_FAILURE(status)) | ||
| 799 | continue; | ||
| 800 | |||
| 801 | pss = buffer.pointer; | ||
| 802 | if (pss && pss->type == ACPI_TYPE_PACKAGE) { | ||
| 803 | kfree(pss); | ||
| 804 | return false; | ||
| 805 | } | ||
| 806 | |||
| 807 | kfree(pss); | ||
| 808 | } | ||
| 809 | |||
| 810 | return true; | ||
| 811 | } | ||
| 812 | |||
| 813 | struct hw_vendor_info { | ||
| 814 | u16 valid; | ||
| 815 | char oem_id[ACPI_OEM_ID_SIZE]; | ||
| 816 | char oem_table_id[ACPI_OEM_TABLE_ID_SIZE]; | ||
| 817 | }; | ||
| 818 | |||
| 819 | /* Hardware vendor-specific info that has its own power management modes */ | ||
| 820 | static struct hw_vendor_info vendor_info[] = { | ||
| 821 | {1, "HP ", "ProLiant"}, | ||
| 822 | {0, "", ""}, | ||
| 823 | }; | ||
| 824 | |||
| 825 | static bool intel_pstate_platform_pwr_mgmt_exists(void) | ||
| 826 | { | ||
| 827 | struct acpi_table_header hdr; | ||
| 828 | struct hw_vendor_info *v_info; | ||
| 829 | |||
| 830 | if (acpi_disabled | ||
| 831 | || ACPI_FAILURE(acpi_get_table_header(ACPI_SIG_FADT, 0, &hdr))) | ||
| 832 | return false; | ||
| 833 | |||
| 834 | for (v_info = vendor_info; v_info->valid; v_info++) { | ||
| 835 | if (!strncmp(hdr.oem_id, v_info->oem_id, ACPI_OEM_ID_SIZE) | ||
| 836 | && !strncmp(hdr.oem_table_id, v_info->oem_table_id, ACPI_OEM_TABLE_ID_SIZE) | ||
| 837 | && intel_pstate_no_acpi_pss()) | ||
| 838 | return true; | ||
| 839 | } | ||
| 840 | |||
| 841 | return false; | ||
| 842 | } | ||
| 843 | #else /* CONFIG_ACPI not enabled */ | ||
| 844 | static inline bool intel_pstate_platform_pwr_mgmt_exists(void) { return false; } | ||
| 845 | #endif /* CONFIG_ACPI */ | ||
| 846 | |||
| 780 | static int __init intel_pstate_init(void) | 847 | static int __init intel_pstate_init(void) |
| 781 | { | 848 | { |
| 782 | int cpu, rc = 0; | 849 | int cpu, rc = 0; |
| @@ -790,6 +857,13 @@ static int __init intel_pstate_init(void) | |||
| 790 | if (!id) | 857 | if (!id) |
| 791 | return -ENODEV; | 858 | return -ENODEV; |
| 792 | 859 | ||
| 860 | /* | ||
| 861 | * The Intel pstate driver will be ignored if the platform | ||
| 862 | * firmware has its own power management modes. | ||
| 863 | */ | ||
| 864 | if (intel_pstate_platform_pwr_mgmt_exists()) | ||
| 865 | return -ENODEV; | ||
| 866 | |||
| 793 | cpu_info = (struct cpu_defaults *)id->driver_data; | 867 | cpu_info = (struct cpu_defaults *)id->driver_data; |
| 794 | 868 | ||
| 795 | copy_pid_params(&cpu_info->pid_policy); | 869 | copy_pid_params(&cpu_info->pid_policy); |
diff --git a/drivers/cpufreq/kirkwood-cpufreq.c b/drivers/cpufreq/kirkwood-cpufreq.c index 0ae4dd7e1f2d..0767a4e29dfe 100644 --- a/drivers/cpufreq/kirkwood-cpufreq.c +++ b/drivers/cpufreq/kirkwood-cpufreq.c | |||
| @@ -58,48 +58,34 @@ static unsigned int kirkwood_cpufreq_get_cpu_frequency(unsigned int cpu) | |||
| 58 | static int kirkwood_cpufreq_target(struct cpufreq_policy *policy, | 58 | static int kirkwood_cpufreq_target(struct cpufreq_policy *policy, |
| 59 | unsigned int index) | 59 | unsigned int index) |
| 60 | { | 60 | { |
| 61 | struct cpufreq_freqs freqs; | ||
| 62 | unsigned int state = kirkwood_freq_table[index].driver_data; | 61 | unsigned int state = kirkwood_freq_table[index].driver_data; |
| 63 | unsigned long reg; | 62 | unsigned long reg; |
| 64 | 63 | ||
| 65 | freqs.old = kirkwood_cpufreq_get_cpu_frequency(0); | 64 | local_irq_disable(); |
| 66 | freqs.new = kirkwood_freq_table[index].frequency; | ||
| 67 | 65 | ||
| 68 | cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); | 66 | /* Disable interrupts to the CPU */ |
| 67 | reg = readl_relaxed(priv.base); | ||
| 68 | reg |= CPU_SW_INT_BLK; | ||
| 69 | writel_relaxed(reg, priv.base); | ||
| 69 | 70 | ||
| 70 | dev_dbg(priv.dev, "Attempting to set frequency to %i KHz\n", | 71 | switch (state) { |
| 71 | kirkwood_freq_table[index].frequency); | 72 | case STATE_CPU_FREQ: |
| 72 | dev_dbg(priv.dev, "old frequency was %i KHz\n", | 73 | clk_disable(priv.powersave_clk); |
| 73 | kirkwood_cpufreq_get_cpu_frequency(0)); | 74 | break; |
| 74 | 75 | case STATE_DDR_FREQ: | |
| 75 | if (freqs.old != freqs.new) { | 76 | clk_enable(priv.powersave_clk); |
| 76 | local_irq_disable(); | 77 | break; |
| 77 | 78 | } | |
| 78 | /* Disable interrupts to the CPU */ | ||
| 79 | reg = readl_relaxed(priv.base); | ||
| 80 | reg |= CPU_SW_INT_BLK; | ||
| 81 | writel_relaxed(reg, priv.base); | ||
| 82 | |||
| 83 | switch (state) { | ||
| 84 | case STATE_CPU_FREQ: | ||
| 85 | clk_disable(priv.powersave_clk); | ||
| 86 | break; | ||
| 87 | case STATE_DDR_FREQ: | ||
| 88 | clk_enable(priv.powersave_clk); | ||
| 89 | break; | ||
| 90 | } | ||
| 91 | 79 | ||
| 92 | /* Wait-for-Interrupt, while the hardware changes frequency */ | 80 | /* Wait-for-Interrupt, while the hardware changes frequency */ |
| 93 | cpu_do_idle(); | 81 | cpu_do_idle(); |
| 94 | 82 | ||
| 95 | /* Enable interrupts to the CPU */ | 83 | /* Enable interrupts to the CPU */ |
| 96 | reg = readl_relaxed(priv.base); | 84 | reg = readl_relaxed(priv.base); |
| 97 | reg &= ~CPU_SW_INT_BLK; | 85 | reg &= ~CPU_SW_INT_BLK; |
| 98 | writel_relaxed(reg, priv.base); | 86 | writel_relaxed(reg, priv.base); |
| 99 | 87 | ||
| 100 | local_irq_enable(); | 88 | local_irq_enable(); |
| 101 | } | ||
| 102 | cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); | ||
| 103 | 89 | ||
| 104 | return 0; | 90 | return 0; |
| 105 | } | 91 | } |
diff --git a/drivers/cpufreq/loongson2_cpufreq.c b/drivers/cpufreq/loongson2_cpufreq.c index 41a8e2cdf940..a43609218105 100644 --- a/drivers/cpufreq/loongson2_cpufreq.c +++ b/drivers/cpufreq/loongson2_cpufreq.c | |||
| @@ -57,7 +57,6 @@ static int loongson2_cpufreq_target(struct cpufreq_policy *policy, | |||
| 57 | { | 57 | { |
| 58 | unsigned int cpu = policy->cpu; | 58 | unsigned int cpu = policy->cpu; |
| 59 | cpumask_t cpus_allowed; | 59 | cpumask_t cpus_allowed; |
| 60 | struct cpufreq_freqs freqs; | ||
| 61 | unsigned int freq; | 60 | unsigned int freq; |
| 62 | 61 | ||
| 63 | cpus_allowed = current->cpus_allowed; | 62 | cpus_allowed = current->cpus_allowed; |
| @@ -67,26 +66,11 @@ static int loongson2_cpufreq_target(struct cpufreq_policy *policy, | |||
| 67 | ((cpu_clock_freq / 1000) * | 66 | ((cpu_clock_freq / 1000) * |
| 68 | loongson2_clockmod_table[index].driver_data) / 8; | 67 | loongson2_clockmod_table[index].driver_data) / 8; |
| 69 | 68 | ||
| 70 | pr_debug("cpufreq: requested frequency %u Hz\n", | ||
| 71 | loongson2_clockmod_table[index].frequency * 1000); | ||
| 72 | |||
| 73 | freqs.old = loongson2_cpufreq_get(cpu); | ||
| 74 | freqs.new = freq; | ||
| 75 | freqs.flags = 0; | ||
| 76 | |||
| 77 | /* notifiers */ | ||
| 78 | cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); | ||
| 79 | |||
| 80 | set_cpus_allowed_ptr(current, &cpus_allowed); | 69 | set_cpus_allowed_ptr(current, &cpus_allowed); |
| 81 | 70 | ||
| 82 | /* setting the cpu frequency */ | 71 | /* setting the cpu frequency */ |
| 83 | clk_set_rate(cpuclk, freq); | 72 | clk_set_rate(cpuclk, freq); |
| 84 | 73 | ||
| 85 | /* notifiers */ | ||
| 86 | cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); | ||
| 87 | |||
| 88 | pr_debug("cpufreq: set frequency %u kHz\n", freq); | ||
| 89 | |||
| 90 | return 0; | 74 | return 0; |
| 91 | } | 75 | } |
| 92 | 76 | ||
diff --git a/drivers/cpufreq/maple-cpufreq.c b/drivers/cpufreq/maple-cpufreq.c index 4e2da0874bfb..c4dfa42a75ac 100644 --- a/drivers/cpufreq/maple-cpufreq.c +++ b/drivers/cpufreq/maple-cpufreq.c | |||
| @@ -69,8 +69,6 @@ static struct cpufreq_frequency_table maple_cpu_freqs[] = { | |||
| 69 | */ | 69 | */ |
| 70 | static int maple_pmode_cur; | 70 | static int maple_pmode_cur; |
| 71 | 71 | ||
| 72 | static DEFINE_MUTEX(maple_switch_mutex); | ||
| 73 | |||
| 74 | static const u32 *maple_pmode_data; | 72 | static const u32 *maple_pmode_data; |
| 75 | static int maple_pmode_max; | 73 | static int maple_pmode_max; |
| 76 | 74 | ||
| @@ -133,21 +131,7 @@ static int maple_scom_query_freq(void) | |||
| 133 | static int maple_cpufreq_target(struct cpufreq_policy *policy, | 131 | static int maple_cpufreq_target(struct cpufreq_policy *policy, |
| 134 | unsigned int index) | 132 | unsigned int index) |
| 135 | { | 133 | { |
| 136 | struct cpufreq_freqs freqs; | 134 | return maple_scom_switch_freq(index); |
| 137 | int rc; | ||
| 138 | |||
| 139 | mutex_lock(&maple_switch_mutex); | ||
| 140 | |||
| 141 | freqs.old = maple_cpu_freqs[maple_pmode_cur].frequency; | ||
| 142 | freqs.new = maple_cpu_freqs[index].frequency; | ||
| 143 | |||
| 144 | cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); | ||
| 145 | rc = maple_scom_switch_freq(index); | ||
| 146 | cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); | ||
| 147 | |||
| 148 | mutex_unlock(&maple_switch_mutex); | ||
| 149 | |||
| 150 | return rc; | ||
| 151 | } | 135 | } |
| 152 | 136 | ||
| 153 | static unsigned int maple_cpufreq_get_speed(unsigned int cpu) | 137 | static unsigned int maple_cpufreq_get_speed(unsigned int cpu) |
diff --git a/drivers/cpufreq/omap-cpufreq.c b/drivers/cpufreq/omap-cpufreq.c index b5512712298f..be6d14307aa8 100644 --- a/drivers/cpufreq/omap-cpufreq.c +++ b/drivers/cpufreq/omap-cpufreq.c | |||
| @@ -53,15 +53,14 @@ static unsigned int omap_getspeed(unsigned int cpu) | |||
| 53 | 53 | ||
| 54 | static int omap_target(struct cpufreq_policy *policy, unsigned int index) | 54 | static int omap_target(struct cpufreq_policy *policy, unsigned int index) |
| 55 | { | 55 | { |
| 56 | int r, ret = 0; | ||
| 57 | struct cpufreq_freqs freqs; | ||
| 58 | struct dev_pm_opp *opp; | 56 | struct dev_pm_opp *opp; |
| 59 | unsigned long freq, volt = 0, volt_old = 0, tol = 0; | 57 | unsigned long freq, volt = 0, volt_old = 0, tol = 0; |
| 58 | unsigned int old_freq, new_freq; | ||
| 60 | 59 | ||
| 61 | freqs.old = omap_getspeed(policy->cpu); | 60 | old_freq = omap_getspeed(policy->cpu); |
| 62 | freqs.new = freq_table[index].frequency; | 61 | new_freq = freq_table[index].frequency; |
| 63 | 62 | ||
| 64 | freq = freqs.new * 1000; | 63 | freq = new_freq * 1000; |
| 65 | ret = clk_round_rate(mpu_clk, freq); | 64 | ret = clk_round_rate(mpu_clk, freq); |
| 66 | if (IS_ERR_VALUE(ret)) { | 65 | if (IS_ERR_VALUE(ret)) { |
| 67 | dev_warn(mpu_dev, | 66 | dev_warn(mpu_dev, |
| @@ -77,7 +76,7 @@ static int omap_target(struct cpufreq_policy *policy, unsigned int index) | |||
| 77 | if (IS_ERR(opp)) { | 76 | if (IS_ERR(opp)) { |
| 78 | rcu_read_unlock(); | 77 | rcu_read_unlock(); |
| 79 | dev_err(mpu_dev, "%s: unable to find MPU OPP for %d\n", | 78 | dev_err(mpu_dev, "%s: unable to find MPU OPP for %d\n", |
| 80 | __func__, freqs.new); | 79 | __func__, new_freq); |
| 81 | return -EINVAL; | 80 | return -EINVAL; |
| 82 | } | 81 | } |
| 83 | volt = dev_pm_opp_get_voltage(opp); | 82 | volt = dev_pm_opp_get_voltage(opp); |
| @@ -87,43 +86,32 @@ static int omap_target(struct cpufreq_policy *policy, unsigned int index) | |||
| 87 | } | 86 | } |
| 88 | 87 | ||
| 89 | dev_dbg(mpu_dev, "cpufreq-omap: %u MHz, %ld mV --> %u MHz, %ld mV\n", | 88 | dev_dbg(mpu_dev, "cpufreq-omap: %u MHz, %ld mV --> %u MHz, %ld mV\n", |
| 90 | freqs.old / 1000, volt_old ? volt_old / 1000 : -1, | 89 | old_freq / 1000, volt_old ? volt_old / 1000 : -1, |
| 91 | freqs.new / 1000, volt ? volt / 1000 : -1); | 90 | new_freq / 1000, volt ? volt / 1000 : -1); |
| 92 | |||
| 93 | /* notifiers */ | ||
| 94 | cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); | ||
| 95 | 91 | ||
| 96 | /* scaling up? scale voltage before frequency */ | 92 | /* scaling up? scale voltage before frequency */ |
| 97 | if (mpu_reg && (freqs.new > freqs.old)) { | 93 | if (mpu_reg && (new_freq > old_freq)) { |
| 98 | r = regulator_set_voltage(mpu_reg, volt - tol, volt + tol); | 94 | r = regulator_set_voltage(mpu_reg, volt - tol, volt + tol); |
| 99 | if (r < 0) { | 95 | if (r < 0) { |
| 100 | dev_warn(mpu_dev, "%s: unable to scale voltage up.\n", | 96 | dev_warn(mpu_dev, "%s: unable to scale voltage up.\n", |
| 101 | __func__); | 97 | __func__); |
| 102 | freqs.new = freqs.old; | 98 | return r; |
| 103 | goto done; | ||
| 104 | } | 99 | } |
| 105 | } | 100 | } |
| 106 | 101 | ||
| 107 | ret = clk_set_rate(mpu_clk, freqs.new * 1000); | 102 | ret = clk_set_rate(mpu_clk, new_freq * 1000); |
| 108 | 103 | ||
| 109 | /* scaling down? scale voltage after frequency */ | 104 | /* scaling down? scale voltage after frequency */ |
| 110 | if (mpu_reg && (freqs.new < freqs.old)) { | 105 | if (mpu_reg && (new_freq < old_freq)) { |
| 111 | r = regulator_set_voltage(mpu_reg, volt - tol, volt + tol); | 106 | r = regulator_set_voltage(mpu_reg, volt - tol, volt + tol); |
| 112 | if (r < 0) { | 107 | if (r < 0) { |
| 113 | dev_warn(mpu_dev, "%s: unable to scale voltage down.\n", | 108 | dev_warn(mpu_dev, "%s: unable to scale voltage down.\n", |
| 114 | __func__); | 109 | __func__); |
| 115 | ret = clk_set_rate(mpu_clk, freqs.old * 1000); | 110 | clk_set_rate(mpu_clk, old_freq * 1000); |
| 116 | freqs.new = freqs.old; | 111 | return r; |
| 117 | goto done; | ||
| 118 | } | 112 | } |
| 119 | } | 113 | } |
| 120 | 114 | ||
| 121 | freqs.new = omap_getspeed(policy->cpu); | ||
| 122 | |||
| 123 | done: | ||
| 124 | /* notifiers */ | ||
| 125 | cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); | ||
| 126 | |||
| 127 | return ret; | 115 | return ret; |
| 128 | } | 116 | } |
| 129 | 117 | ||
diff --git a/drivers/cpufreq/p4-clockmod.c b/drivers/cpufreq/p4-clockmod.c index 3c23053afdfd..3d1cba9fd5f9 100644 --- a/drivers/cpufreq/p4-clockmod.c +++ b/drivers/cpufreq/p4-clockmod.c | |||
| @@ -107,15 +107,8 @@ static struct cpufreq_frequency_table p4clockmod_table[] = { | |||
| 107 | 107 | ||
| 108 | static int cpufreq_p4_target(struct cpufreq_policy *policy, unsigned int index) | 108 | static int cpufreq_p4_target(struct cpufreq_policy *policy, unsigned int index) |
| 109 | { | 109 | { |
| 110 | struct cpufreq_freqs freqs; | ||
| 111 | int i; | 110 | int i; |
| 112 | 111 | ||
| 113 | freqs.old = cpufreq_p4_get(policy->cpu); | ||
| 114 | freqs.new = stock_freq * p4clockmod_table[index].driver_data / 8; | ||
| 115 | |||
| 116 | /* notifiers */ | ||
| 117 | cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); | ||
| 118 | |||
| 119 | /* run on each logical CPU, | 112 | /* run on each logical CPU, |
| 120 | * see section 13.15.3 of IA32 Intel Architecture Software | 113 | * see section 13.15.3 of IA32 Intel Architecture Software |
| 121 | * Developer's Manual, Volume 3 | 114 | * Developer's Manual, Volume 3 |
| @@ -123,9 +116,6 @@ static int cpufreq_p4_target(struct cpufreq_policy *policy, unsigned int index) | |||
| 123 | for_each_cpu(i, policy->cpus) | 116 | for_each_cpu(i, policy->cpus) |
| 124 | cpufreq_p4_setdc(i, p4clockmod_table[index].driver_data); | 117 | cpufreq_p4_setdc(i, p4clockmod_table[index].driver_data); |
| 125 | 118 | ||
| 126 | /* notifiers */ | ||
| 127 | cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); | ||
| 128 | |||
| 129 | return 0; | 119 | return 0; |
| 130 | } | 120 | } |
| 131 | 121 | ||
diff --git a/drivers/cpufreq/pasemi-cpufreq.c b/drivers/cpufreq/pasemi-cpufreq.c index 17424ddc7f67..1c331369b15b 100644 --- a/drivers/cpufreq/pasemi-cpufreq.c +++ b/drivers/cpufreq/pasemi-cpufreq.c | |||
| @@ -51,8 +51,6 @@ | |||
| 51 | static void __iomem *sdcpwr_mapbase; | 51 | static void __iomem *sdcpwr_mapbase; |
| 52 | static void __iomem *sdcasr_mapbase; | 52 | static void __iomem *sdcasr_mapbase; |
| 53 | 53 | ||
| 54 | static DEFINE_MUTEX(pas_switch_mutex); | ||
| 55 | |||
| 56 | /* Current astate, is used when waking up from power savings on | 54 | /* Current astate, is used when waking up from power savings on |
| 57 | * one core, in case the other core has switched states during | 55 | * one core, in case the other core has switched states during |
| 58 | * the idle time. | 56 | * the idle time. |
| @@ -242,15 +240,8 @@ static int pas_cpufreq_cpu_exit(struct cpufreq_policy *policy) | |||
| 242 | static int pas_cpufreq_target(struct cpufreq_policy *policy, | 240 | static int pas_cpufreq_target(struct cpufreq_policy *policy, |
| 243 | unsigned int pas_astate_new) | 241 | unsigned int pas_astate_new) |
| 244 | { | 242 | { |
| 245 | struct cpufreq_freqs freqs; | ||
| 246 | int i; | 243 | int i; |
| 247 | 244 | ||
| 248 | freqs.old = policy->cur; | ||
| 249 | freqs.new = pas_freqs[pas_astate_new].frequency; | ||
| 250 | |||
| 251 | mutex_lock(&pas_switch_mutex); | ||
| 252 | cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); | ||
| 253 | |||
| 254 | pr_debug("setting frequency for cpu %d to %d kHz, 1/%d of max frequency\n", | 245 | pr_debug("setting frequency for cpu %d to %d kHz, 1/%d of max frequency\n", |
| 255 | policy->cpu, | 246 | policy->cpu, |
| 256 | pas_freqs[pas_astate_new].frequency, | 247 | pas_freqs[pas_astate_new].frequency, |
| @@ -261,10 +252,7 @@ static int pas_cpufreq_target(struct cpufreq_policy *policy, | |||
| 261 | for_each_online_cpu(i) | 252 | for_each_online_cpu(i) |
| 262 | set_astate(i, pas_astate_new); | 253 | set_astate(i, pas_astate_new); |
| 263 | 254 | ||
| 264 | cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); | 255 | ppc_proc_freq = pas_freqs[pas_astate_new].frequency * 1000ul; |
| 265 | mutex_unlock(&pas_switch_mutex); | ||
| 266 | |||
| 267 | ppc_proc_freq = freqs.new * 1000ul; | ||
| 268 | return 0; | 256 | return 0; |
| 269 | } | 257 | } |
| 270 | 258 | ||
diff --git a/drivers/cpufreq/pmac32-cpufreq.c b/drivers/cpufreq/pmac32-cpufreq.c index 05f705e1b7a2..cf55d202f332 100644 --- a/drivers/cpufreq/pmac32-cpufreq.c +++ b/drivers/cpufreq/pmac32-cpufreq.c | |||
| @@ -331,21 +331,11 @@ static int pmu_set_cpu_speed(int low_speed) | |||
| 331 | return 0; | 331 | return 0; |
| 332 | } | 332 | } |
| 333 | 333 | ||
| 334 | static int do_set_cpu_speed(struct cpufreq_policy *policy, int speed_mode, | 334 | static int do_set_cpu_speed(struct cpufreq_policy *policy, int speed_mode) |
| 335 | int notify) | ||
| 336 | { | 335 | { |
| 337 | struct cpufreq_freqs freqs; | ||
| 338 | unsigned long l3cr; | 336 | unsigned long l3cr; |
| 339 | static unsigned long prev_l3cr; | 337 | static unsigned long prev_l3cr; |
| 340 | 338 | ||
| 341 | freqs.old = cur_freq; | ||
| 342 | freqs.new = (speed_mode == CPUFREQ_HIGH) ? hi_freq : low_freq; | ||
| 343 | |||
| 344 | if (freqs.old == freqs.new) | ||
| 345 | return 0; | ||
| 346 | |||
| 347 | if (notify) | ||
| 348 | cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); | ||
| 349 | if (speed_mode == CPUFREQ_LOW && | 339 | if (speed_mode == CPUFREQ_LOW && |
| 350 | cpu_has_feature(CPU_FTR_L3CR)) { | 340 | cpu_has_feature(CPU_FTR_L3CR)) { |
| 351 | l3cr = _get_L3CR(); | 341 | l3cr = _get_L3CR(); |
| @@ -361,8 +351,6 @@ static int do_set_cpu_speed(struct cpufreq_policy *policy, int speed_mode, | |||
| 361 | if ((prev_l3cr & L3CR_L3E) && l3cr != prev_l3cr) | 351 | if ((prev_l3cr & L3CR_L3E) && l3cr != prev_l3cr) |
| 362 | _set_L3CR(prev_l3cr); | 352 | _set_L3CR(prev_l3cr); |
| 363 | } | 353 | } |
| 364 | if (notify) | ||
| 365 | cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); | ||
| 366 | cur_freq = (speed_mode == CPUFREQ_HIGH) ? hi_freq : low_freq; | 354 | cur_freq = (speed_mode == CPUFREQ_HIGH) ? hi_freq : low_freq; |
| 367 | 355 | ||
| 368 | return 0; | 356 | return 0; |
| @@ -378,7 +366,7 @@ static int pmac_cpufreq_target( struct cpufreq_policy *policy, | |||
| 378 | { | 366 | { |
| 379 | int rc; | 367 | int rc; |
| 380 | 368 | ||
| 381 | rc = do_set_cpu_speed(policy, index, 1); | 369 | rc = do_set_cpu_speed(policy, index); |
| 382 | 370 | ||
| 383 | ppc_proc_freq = cur_freq * 1000ul; | 371 | ppc_proc_freq = cur_freq * 1000ul; |
| 384 | return rc; | 372 | return rc; |
| @@ -420,7 +408,7 @@ static int pmac_cpufreq_suspend(struct cpufreq_policy *policy) | |||
| 420 | no_schedule = 1; | 408 | no_schedule = 1; |
| 421 | sleep_freq = cur_freq; | 409 | sleep_freq = cur_freq; |
| 422 | if (cur_freq == low_freq && !is_pmu_based) | 410 | if (cur_freq == low_freq && !is_pmu_based) |
| 423 | do_set_cpu_speed(policy, CPUFREQ_HIGH, 0); | 411 | do_set_cpu_speed(policy, CPUFREQ_HIGH); |
| 424 | return 0; | 412 | return 0; |
| 425 | } | 413 | } |
| 426 | 414 | ||
| @@ -437,7 +425,7 @@ static int pmac_cpufreq_resume(struct cpufreq_policy *policy) | |||
| 437 | * probably high speed due to our suspend() routine | 425 | * probably high speed due to our suspend() routine |
| 438 | */ | 426 | */ |
| 439 | do_set_cpu_speed(policy, sleep_freq == low_freq ? | 427 | do_set_cpu_speed(policy, sleep_freq == low_freq ? |
| 440 | CPUFREQ_LOW : CPUFREQ_HIGH, 0); | 428 | CPUFREQ_LOW : CPUFREQ_HIGH); |
| 441 | 429 | ||
| 442 | ppc_proc_freq = cur_freq * 1000ul; | 430 | ppc_proc_freq = cur_freq * 1000ul; |
| 443 | 431 | ||
diff --git a/drivers/cpufreq/pmac64-cpufreq.c b/drivers/cpufreq/pmac64-cpufreq.c index 234b598ce416..6a338f8c3860 100644 --- a/drivers/cpufreq/pmac64-cpufreq.c +++ b/drivers/cpufreq/pmac64-cpufreq.c | |||
| @@ -79,8 +79,6 @@ static void (*g5_switch_volt)(int speed_mode); | |||
| 79 | static int (*g5_switch_freq)(int speed_mode); | 79 | static int (*g5_switch_freq)(int speed_mode); |
| 80 | static int (*g5_query_freq)(void); | 80 | static int (*g5_query_freq)(void); |
| 81 | 81 | ||
| 82 | static DEFINE_MUTEX(g5_switch_mutex); | ||
| 83 | |||
| 84 | static unsigned long transition_latency; | 82 | static unsigned long transition_latency; |
| 85 | 83 | ||
| 86 | #ifdef CONFIG_PMAC_SMU | 84 | #ifdef CONFIG_PMAC_SMU |
| @@ -314,21 +312,7 @@ static int g5_pfunc_query_freq(void) | |||
| 314 | 312 | ||
| 315 | static int g5_cpufreq_target(struct cpufreq_policy *policy, unsigned int index) | 313 | static int g5_cpufreq_target(struct cpufreq_policy *policy, unsigned int index) |
| 316 | { | 314 | { |
| 317 | struct cpufreq_freqs freqs; | 315 | return g5_switch_freq(index); |
| 318 | int rc; | ||
| 319 | |||
| 320 | mutex_lock(&g5_switch_mutex); | ||
| 321 | |||
| 322 | freqs.old = g5_cpu_freqs[g5_pmode_cur].frequency; | ||
| 323 | freqs.new = g5_cpu_freqs[index].frequency; | ||
| 324 | |||
| 325 | cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); | ||
| 326 | rc = g5_switch_freq(index); | ||
| 327 | cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); | ||
| 328 | |||
| 329 | mutex_unlock(&g5_switch_mutex); | ||
| 330 | |||
| 331 | return rc; | ||
| 332 | } | 316 | } |
| 333 | 317 | ||
| 334 | static unsigned int g5_cpufreq_get_speed(unsigned int cpu) | 318 | static unsigned int g5_cpufreq_get_speed(unsigned int cpu) |
diff --git a/drivers/cpufreq/powernow-k8.c b/drivers/cpufreq/powernow-k8.c index 62a1ce47d3df..0023c7d40a51 100644 --- a/drivers/cpufreq/powernow-k8.c +++ b/drivers/cpufreq/powernow-k8.c | |||
| @@ -1204,6 +1204,7 @@ out: | |||
| 1204 | } | 1204 | } |
| 1205 | 1205 | ||
| 1206 | static struct cpufreq_driver cpufreq_amd64_driver = { | 1206 | static struct cpufreq_driver cpufreq_amd64_driver = { |
| 1207 | .flags = CPUFREQ_ASYNC_NOTIFICATION, | ||
| 1207 | .verify = cpufreq_generic_frequency_table_verify, | 1208 | .verify = cpufreq_generic_frequency_table_verify, |
| 1208 | .target_index = powernowk8_target, | 1209 | .target_index = powernowk8_target, |
| 1209 | .bios_limit = acpi_processor_get_bios_limit, | 1210 | .bios_limit = acpi_processor_get_bios_limit, |
diff --git a/drivers/cpufreq/ppc-corenet-cpufreq.c b/drivers/cpufreq/ppc-corenet-cpufreq.c index 79d8e9c46b6d..3f7be46d2b27 100644 --- a/drivers/cpufreq/ppc-corenet-cpufreq.c +++ b/drivers/cpufreq/ppc-corenet-cpufreq.c | |||
| @@ -69,8 +69,6 @@ static const struct soc_data sdata[] = { | |||
| 69 | static u32 min_cpufreq; | 69 | static u32 min_cpufreq; |
| 70 | static const u32 *fmask; | 70 | static const u32 *fmask; |
| 71 | 71 | ||
| 72 | /* serialize frequency changes */ | ||
| 73 | static DEFINE_MUTEX(cpufreq_lock); | ||
| 74 | static DEFINE_PER_CPU(struct cpu_data *, cpu_data); | 72 | static DEFINE_PER_CPU(struct cpu_data *, cpu_data); |
| 75 | 73 | ||
| 76 | /* cpumask in a cluster */ | 74 | /* cpumask in a cluster */ |
| @@ -253,26 +251,11 @@ static int __exit corenet_cpufreq_cpu_exit(struct cpufreq_policy *policy) | |||
| 253 | static int corenet_cpufreq_target(struct cpufreq_policy *policy, | 251 | static int corenet_cpufreq_target(struct cpufreq_policy *policy, |
| 254 | unsigned int index) | 252 | unsigned int index) |
| 255 | { | 253 | { |
| 256 | struct cpufreq_freqs freqs; | ||
| 257 | struct clk *parent; | 254 | struct clk *parent; |
| 258 | int ret; | ||
| 259 | struct cpu_data *data = per_cpu(cpu_data, policy->cpu); | 255 | struct cpu_data *data = per_cpu(cpu_data, policy->cpu); |
| 260 | 256 | ||
| 261 | freqs.old = policy->cur; | ||
| 262 | freqs.new = data->table[index].frequency; | ||
| 263 | |||
| 264 | mutex_lock(&cpufreq_lock); | ||
| 265 | cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); | ||
| 266 | |||
| 267 | parent = of_clk_get(data->parent, data->table[index].driver_data); | 257 | parent = of_clk_get(data->parent, data->table[index].driver_data); |
| 268 | ret = clk_set_parent(data->clk, parent); | 258 | return clk_set_parent(data->clk, parent); |
| 269 | if (ret) | ||
| 270 | freqs.new = freqs.old; | ||
| 271 | |||
| 272 | cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); | ||
| 273 | mutex_unlock(&cpufreq_lock); | ||
| 274 | |||
| 275 | return ret; | ||
| 276 | } | 259 | } |
| 277 | 260 | ||
| 278 | static struct cpufreq_driver ppc_corenet_cpufreq_driver = { | 261 | static struct cpufreq_driver ppc_corenet_cpufreq_driver = { |
diff --git a/drivers/cpufreq/ppc_cbe_cpufreq.c b/drivers/cpufreq/ppc_cbe_cpufreq.c index 52f707d5f458..e42ca9c31cea 100644 --- a/drivers/cpufreq/ppc_cbe_cpufreq.c +++ b/drivers/cpufreq/ppc_cbe_cpufreq.c | |||
| @@ -30,9 +30,6 @@ | |||
| 30 | 30 | ||
| 31 | #include "ppc_cbe_cpufreq.h" | 31 | #include "ppc_cbe_cpufreq.h" |
| 32 | 32 | ||
| 33 | static DEFINE_MUTEX(cbe_switch_mutex); | ||
| 34 | |||
| 35 | |||
| 36 | /* the CBE supports an 8 step frequency scaling */ | 33 | /* the CBE supports an 8 step frequency scaling */ |
| 37 | static struct cpufreq_frequency_table cbe_freqs[] = { | 34 | static struct cpufreq_frequency_table cbe_freqs[] = { |
| 38 | {1, 0}, | 35 | {1, 0}, |
| @@ -131,27 +128,13 @@ static int cbe_cpufreq_cpu_init(struct cpufreq_policy *policy) | |||
| 131 | static int cbe_cpufreq_target(struct cpufreq_policy *policy, | 128 | static int cbe_cpufreq_target(struct cpufreq_policy *policy, |
| 132 | unsigned int cbe_pmode_new) | 129 | unsigned int cbe_pmode_new) |
| 133 | { | 130 | { |
| 134 | int rc; | ||
| 135 | struct cpufreq_freqs freqs; | ||
| 136 | |||
| 137 | freqs.old = policy->cur; | ||
| 138 | freqs.new = cbe_freqs[cbe_pmode_new].frequency; | ||
| 139 | |||
| 140 | mutex_lock(&cbe_switch_mutex); | ||
| 141 | cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); | ||
| 142 | |||
| 143 | pr_debug("setting frequency for cpu %d to %d kHz, " \ | 131 | pr_debug("setting frequency for cpu %d to %d kHz, " \ |
| 144 | "1/%d of max frequency\n", | 132 | "1/%d of max frequency\n", |
| 145 | policy->cpu, | 133 | policy->cpu, |
| 146 | cbe_freqs[cbe_pmode_new].frequency, | 134 | cbe_freqs[cbe_pmode_new].frequency, |
| 147 | cbe_freqs[cbe_pmode_new].driver_data); | 135 | cbe_freqs[cbe_pmode_new].driver_data); |
| 148 | 136 | ||
| 149 | rc = set_pmode(policy->cpu, cbe_pmode_new); | 137 | return set_pmode(policy->cpu, cbe_pmode_new); |
| 150 | |||
| 151 | cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); | ||
| 152 | mutex_unlock(&cbe_switch_mutex); | ||
| 153 | |||
| 154 | return rc; | ||
| 155 | } | 138 | } |
| 156 | 139 | ||
| 157 | static struct cpufreq_driver cbe_cpufreq_driver = { | 140 | static struct cpufreq_driver cbe_cpufreq_driver = { |
diff --git a/drivers/cpufreq/pxa2xx-cpufreq.c b/drivers/cpufreq/pxa2xx-cpufreq.c index 183bc13f13e5..0a0f4369636a 100644 --- a/drivers/cpufreq/pxa2xx-cpufreq.c +++ b/drivers/cpufreq/pxa2xx-cpufreq.c | |||
| @@ -271,7 +271,6 @@ static int pxa_set_target(struct cpufreq_policy *policy, unsigned int idx) | |||
| 271 | { | 271 | { |
| 272 | struct cpufreq_frequency_table *pxa_freqs_table; | 272 | struct cpufreq_frequency_table *pxa_freqs_table; |
| 273 | pxa_freqs_t *pxa_freq_settings; | 273 | pxa_freqs_t *pxa_freq_settings; |
| 274 | struct cpufreq_freqs freqs; | ||
| 275 | unsigned long flags; | 274 | unsigned long flags; |
| 276 | unsigned int new_freq_cpu, new_freq_mem; | 275 | unsigned int new_freq_cpu, new_freq_mem; |
| 277 | unsigned int unused, preset_mdrefr, postset_mdrefr, cclkcfg; | 276 | unsigned int unused, preset_mdrefr, postset_mdrefr, cclkcfg; |
| @@ -282,24 +281,17 @@ static int pxa_set_target(struct cpufreq_policy *policy, unsigned int idx) | |||
| 282 | 281 | ||
| 283 | new_freq_cpu = pxa_freq_settings[idx].khz; | 282 | new_freq_cpu = pxa_freq_settings[idx].khz; |
| 284 | new_freq_mem = pxa_freq_settings[idx].membus; | 283 | new_freq_mem = pxa_freq_settings[idx].membus; |
| 285 | freqs.old = policy->cur; | ||
| 286 | freqs.new = new_freq_cpu; | ||
| 287 | 284 | ||
| 288 | if (freq_debug) | 285 | if (freq_debug) |
| 289 | pr_debug("Changing CPU frequency to %d Mhz, (SDRAM %d Mhz)\n", | 286 | pr_debug("Changing CPU frequency to %d Mhz, (SDRAM %d Mhz)\n", |
| 290 | freqs.new / 1000, (pxa_freq_settings[idx].div2) ? | 287 | new_freq_cpu / 1000, (pxa_freq_settings[idx].div2) ? |
| 291 | (new_freq_mem / 2000) : (new_freq_mem / 1000)); | 288 | (new_freq_mem / 2000) : (new_freq_mem / 1000)); |
| 292 | 289 | ||
| 293 | if (vcc_core && freqs.new > freqs.old) | 290 | if (vcc_core && new_freq_cpu > policy->cur) { |
| 294 | ret = pxa_cpufreq_change_voltage(&pxa_freq_settings[idx]); | 291 | ret = pxa_cpufreq_change_voltage(&pxa_freq_settings[idx]); |
| 295 | if (ret) | 292 | if (ret) |
| 296 | return ret; | 293 | return ret; |
| 297 | /* | 294 | } |
| 298 | * Tell everyone what we're about to do... | ||
| 299 | * you should add a notify client with any platform specific | ||
| 300 | * Vcc changing capability | ||
| 301 | */ | ||
| 302 | cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); | ||
| 303 | 295 | ||
| 304 | /* Calculate the next MDREFR. If we're slowing down the SDRAM clock | 296 | /* Calculate the next MDREFR. If we're slowing down the SDRAM clock |
| 305 | * we need to preset the smaller DRI before the change. If we're | 297 | * we need to preset the smaller DRI before the change. If we're |
| @@ -350,13 +342,6 @@ static int pxa_set_target(struct cpufreq_policy *policy, unsigned int idx) | |||
| 350 | local_irq_restore(flags); | 342 | local_irq_restore(flags); |
| 351 | 343 | ||
| 352 | /* | 344 | /* |
| 353 | * Tell everyone what we've just done... | ||
| 354 | * you should add a notify client with any platform specific | ||
| 355 | * SDRAM refresh timer adjustments | ||
| 356 | */ | ||
| 357 | cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); | ||
| 358 | |||
| 359 | /* | ||
| 360 | * Even if voltage setting fails, we don't report it, as the frequency | 345 | * Even if voltage setting fails, we don't report it, as the frequency |
| 361 | * change succeeded. The voltage reduction is not a critical failure, | 346 | * change succeeded. The voltage reduction is not a critical failure, |
| 362 | * only power savings will suffer from this. | 347 | * only power savings will suffer from this. |
| @@ -365,7 +350,7 @@ static int pxa_set_target(struct cpufreq_policy *policy, unsigned int idx) | |||
| 365 | * bug is triggered (seems a deadlock). Should anybody find out where, | 350 | * bug is triggered (seems a deadlock). Should anybody find out where, |
| 366 | * the "return 0" should become a "return ret". | 351 | * the "return 0" should become a "return ret". |
| 367 | */ | 352 | */ |
| 368 | if (vcc_core && freqs.new < freqs.old) | 353 | if (vcc_core && new_freq_cpu < policy->cur) |
| 369 | ret = pxa_cpufreq_change_voltage(&pxa_freq_settings[idx]); | 354 | ret = pxa_cpufreq_change_voltage(&pxa_freq_settings[idx]); |
| 370 | 355 | ||
| 371 | return 0; | 356 | return 0; |
diff --git a/drivers/cpufreq/pxa3xx-cpufreq.c b/drivers/cpufreq/pxa3xx-cpufreq.c index 132e37d578c2..93840048dd11 100644 --- a/drivers/cpufreq/pxa3xx-cpufreq.c +++ b/drivers/cpufreq/pxa3xx-cpufreq.c | |||
| @@ -158,7 +158,6 @@ static unsigned int pxa3xx_cpufreq_get(unsigned int cpu) | |||
| 158 | static int pxa3xx_cpufreq_set(struct cpufreq_policy *policy, unsigned int index) | 158 | static int pxa3xx_cpufreq_set(struct cpufreq_policy *policy, unsigned int index) |
| 159 | { | 159 | { |
| 160 | struct pxa3xx_freq_info *next; | 160 | struct pxa3xx_freq_info *next; |
| 161 | struct cpufreq_freqs freqs; | ||
| 162 | unsigned long flags; | 161 | unsigned long flags; |
| 163 | 162 | ||
| 164 | if (policy->cpu != 0) | 163 | if (policy->cpu != 0) |
| @@ -166,22 +165,11 @@ static int pxa3xx_cpufreq_set(struct cpufreq_policy *policy, unsigned int index) | |||
| 166 | 165 | ||
| 167 | next = &pxa3xx_freqs[index]; | 166 | next = &pxa3xx_freqs[index]; |
| 168 | 167 | ||
| 169 | freqs.old = policy->cur; | ||
| 170 | freqs.new = next->cpufreq_mhz * 1000; | ||
| 171 | |||
| 172 | pr_debug("CPU frequency from %d MHz to %d MHz%s\n", | ||
| 173 | freqs.old / 1000, freqs.new / 1000, | ||
| 174 | (freqs.old == freqs.new) ? " (skipped)" : ""); | ||
| 175 | |||
| 176 | cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); | ||
| 177 | |||
| 178 | local_irq_save(flags); | 168 | local_irq_save(flags); |
| 179 | __update_core_freq(next); | 169 | __update_core_freq(next); |
| 180 | __update_bus_freq(next); | 170 | __update_bus_freq(next); |
| 181 | local_irq_restore(flags); | 171 | local_irq_restore(flags); |
| 182 | 172 | ||
| 183 | cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); | ||
| 184 | |||
| 185 | return 0; | 173 | return 0; |
| 186 | } | 174 | } |
| 187 | 175 | ||
diff --git a/drivers/cpufreq/s3c2416-cpufreq.c b/drivers/cpufreq/s3c2416-cpufreq.c index 4188accd34ab..8d904a00027b 100644 --- a/drivers/cpufreq/s3c2416-cpufreq.c +++ b/drivers/cpufreq/s3c2416-cpufreq.c | |||
| @@ -220,7 +220,7 @@ static int s3c2416_cpufreq_set_target(struct cpufreq_policy *policy, | |||
| 220 | unsigned int index) | 220 | unsigned int index) |
| 221 | { | 221 | { |
| 222 | struct s3c2416_data *s3c_freq = &s3c2416_cpufreq; | 222 | struct s3c2416_data *s3c_freq = &s3c2416_cpufreq; |
| 223 | struct cpufreq_freqs freqs; | 223 | unsigned int new_freq; |
| 224 | int idx, ret, to_dvs = 0; | 224 | int idx, ret, to_dvs = 0; |
| 225 | 225 | ||
| 226 | mutex_lock(&cpufreq_lock); | 226 | mutex_lock(&cpufreq_lock); |
| @@ -237,25 +237,14 @@ static int s3c2416_cpufreq_set_target(struct cpufreq_policy *policy, | |||
| 237 | goto out; | 237 | goto out; |
| 238 | } | 238 | } |
| 239 | 239 | ||
| 240 | freqs.flags = 0; | ||
| 241 | freqs.old = s3c_freq->is_dvs ? FREQ_DVS | ||
| 242 | : clk_get_rate(s3c_freq->armclk) / 1000; | ||
| 243 | |||
| 244 | /* When leavin dvs mode, always switch the armdiv to the hclk rate | 240 | /* When leavin dvs mode, always switch the armdiv to the hclk rate |
| 245 | * The S3C2416 has stability issues when switching directly to | 241 | * The S3C2416 has stability issues when switching directly to |
| 246 | * higher frequencies. | 242 | * higher frequencies. |
| 247 | */ | 243 | */ |
| 248 | freqs.new = (s3c_freq->is_dvs && !to_dvs) | 244 | new_freq = (s3c_freq->is_dvs && !to_dvs) |
| 249 | ? clk_get_rate(s3c_freq->hclk) / 1000 | 245 | ? clk_get_rate(s3c_freq->hclk) / 1000 |
| 250 | : s3c_freq->freq_table[index].frequency; | 246 | : s3c_freq->freq_table[index].frequency; |
| 251 | 247 | ||
| 252 | pr_debug("cpufreq: Transition %d-%dkHz\n", freqs.old, freqs.new); | ||
| 253 | |||
| 254 | if (!to_dvs && freqs.old == freqs.new) | ||
| 255 | goto out; | ||
| 256 | |||
| 257 | cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); | ||
| 258 | |||
| 259 | if (to_dvs) { | 248 | if (to_dvs) { |
| 260 | pr_debug("cpufreq: enter dvs\n"); | 249 | pr_debug("cpufreq: enter dvs\n"); |
| 261 | ret = s3c2416_cpufreq_enter_dvs(s3c_freq, idx); | 250 | ret = s3c2416_cpufreq_enter_dvs(s3c_freq, idx); |
| @@ -263,12 +252,10 @@ static int s3c2416_cpufreq_set_target(struct cpufreq_policy *policy, | |||
| 263 | pr_debug("cpufreq: leave dvs\n"); | 252 | pr_debug("cpufreq: leave dvs\n"); |
| 264 | ret = s3c2416_cpufreq_leave_dvs(s3c_freq, idx); | 253 | ret = s3c2416_cpufreq_leave_dvs(s3c_freq, idx); |
| 265 | } else { | 254 | } else { |
| 266 | pr_debug("cpufreq: change armdiv to %dkHz\n", freqs.new); | 255 | pr_debug("cpufreq: change armdiv to %dkHz\n", new_freq); |
| 267 | ret = s3c2416_cpufreq_set_armdiv(s3c_freq, freqs.new); | 256 | ret = s3c2416_cpufreq_set_armdiv(s3c_freq, new_freq); |
| 268 | } | 257 | } |
| 269 | 258 | ||
| 270 | cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); | ||
| 271 | |||
| 272 | out: | 259 | out: |
| 273 | mutex_unlock(&cpufreq_lock); | 260 | mutex_unlock(&cpufreq_lock); |
| 274 | 261 | ||
diff --git a/drivers/cpufreq/s3c64xx-cpufreq.c b/drivers/cpufreq/s3c64xx-cpufreq.c index 8bdcf32a4418..67e302eeefec 100644 --- a/drivers/cpufreq/s3c64xx-cpufreq.c +++ b/drivers/cpufreq/s3c64xx-cpufreq.c | |||
| @@ -65,54 +65,46 @@ static unsigned int s3c64xx_cpufreq_get_speed(unsigned int cpu) | |||
| 65 | static int s3c64xx_cpufreq_set_target(struct cpufreq_policy *policy, | 65 | static int s3c64xx_cpufreq_set_target(struct cpufreq_policy *policy, |
| 66 | unsigned int index) | 66 | unsigned int index) |
| 67 | { | 67 | { |
| 68 | int ret; | ||
| 69 | struct cpufreq_freqs freqs; | ||
| 70 | struct s3c64xx_dvfs *dvfs; | 68 | struct s3c64xx_dvfs *dvfs; |
| 69 | unsigned int old_freq, new_freq; | ||
| 70 | int ret; | ||
| 71 | 71 | ||
| 72 | freqs.old = clk_get_rate(armclk) / 1000; | 72 | old_freq = clk_get_rate(armclk) / 1000; |
| 73 | freqs.new = s3c64xx_freq_table[index].frequency; | 73 | new_freq = s3c64xx_freq_table[index].frequency; |
| 74 | freqs.flags = 0; | ||
| 75 | dvfs = &s3c64xx_dvfs_table[s3c64xx_freq_table[index].driver_data]; | 74 | dvfs = &s3c64xx_dvfs_table[s3c64xx_freq_table[index].driver_data]; |
| 76 | 75 | ||
| 77 | pr_debug("Transition %d-%dkHz\n", freqs.old, freqs.new); | ||
| 78 | |||
| 79 | cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); | ||
| 80 | |||
| 81 | #ifdef CONFIG_REGULATOR | 76 | #ifdef CONFIG_REGULATOR |
| 82 | if (vddarm && freqs.new > freqs.old) { | 77 | if (vddarm && new_freq > old_freq) { |
| 83 | ret = regulator_set_voltage(vddarm, | 78 | ret = regulator_set_voltage(vddarm, |
| 84 | dvfs->vddarm_min, | 79 | dvfs->vddarm_min, |
| 85 | dvfs->vddarm_max); | 80 | dvfs->vddarm_max); |
| 86 | if (ret != 0) { | 81 | if (ret != 0) { |
| 87 | pr_err("Failed to set VDDARM for %dkHz: %d\n", | 82 | pr_err("Failed to set VDDARM for %dkHz: %d\n", |
| 88 | freqs.new, ret); | 83 | new_freq, ret); |
| 89 | freqs.new = freqs.old; | 84 | return ret; |
| 90 | goto post_notify; | ||
| 91 | } | 85 | } |
| 92 | } | 86 | } |
| 93 | #endif | 87 | #endif |
| 94 | 88 | ||
| 95 | ret = clk_set_rate(armclk, freqs.new * 1000); | 89 | ret = clk_set_rate(armclk, new_freq * 1000); |
| 96 | if (ret < 0) { | 90 | if (ret < 0) { |
| 97 | pr_err("Failed to set rate %dkHz: %d\n", | 91 | pr_err("Failed to set rate %dkHz: %d\n", |
| 98 | freqs.new, ret); | 92 | new_freq, ret); |
| 99 | freqs.new = freqs.old; | 93 | return ret; |
| 100 | } | 94 | } |
| 101 | 95 | ||
| 102 | post_notify: | ||
| 103 | cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); | ||
| 104 | if (ret) | ||
| 105 | goto err; | ||
| 106 | |||
| 107 | #ifdef CONFIG_REGULATOR | 96 | #ifdef CONFIG_REGULATOR |
| 108 | if (vddarm && freqs.new < freqs.old) { | 97 | if (vddarm && new_freq < old_freq) { |
| 109 | ret = regulator_set_voltage(vddarm, | 98 | ret = regulator_set_voltage(vddarm, |
| 110 | dvfs->vddarm_min, | 99 | dvfs->vddarm_min, |
| 111 | dvfs->vddarm_max); | 100 | dvfs->vddarm_max); |
| 112 | if (ret != 0) { | 101 | if (ret != 0) { |
| 113 | pr_err("Failed to set VDDARM for %dkHz: %d\n", | 102 | pr_err("Failed to set VDDARM for %dkHz: %d\n", |
| 114 | freqs.new, ret); | 103 | new_freq, ret); |
| 115 | goto err_clk; | 104 | if (clk_set_rate(armclk, old_freq * 1000) < 0) |
| 105 | pr_err("Failed to restore original clock rate\n"); | ||
| 106 | |||
| 107 | return ret; | ||
| 116 | } | 108 | } |
| 117 | } | 109 | } |
| 118 | #endif | 110 | #endif |
| @@ -121,14 +113,6 @@ post_notify: | |||
| 121 | clk_get_rate(armclk) / 1000); | 113 | clk_get_rate(armclk) / 1000); |
| 122 | 114 | ||
| 123 | return 0; | 115 | return 0; |
| 124 | |||
| 125 | err_clk: | ||
| 126 | if (clk_set_rate(armclk, freqs.old * 1000) < 0) | ||
| 127 | pr_err("Failed to restore original clock rate\n"); | ||
| 128 | err: | ||
| 129 | cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); | ||
| 130 | |||
| 131 | return ret; | ||
| 132 | } | 116 | } |
| 133 | 117 | ||
| 134 | #ifdef CONFIG_REGULATOR | 118 | #ifdef CONFIG_REGULATOR |
diff --git a/drivers/cpufreq/s5pv210-cpufreq.c b/drivers/cpufreq/s5pv210-cpufreq.c index 5978b94e0340..e3973dae28a7 100644 --- a/drivers/cpufreq/s5pv210-cpufreq.c +++ b/drivers/cpufreq/s5pv210-cpufreq.c | |||
| @@ -26,7 +26,6 @@ | |||
| 26 | static struct clk *cpu_clk; | 26 | static struct clk *cpu_clk; |
| 27 | static struct clk *dmc0_clk; | 27 | static struct clk *dmc0_clk; |
| 28 | static struct clk *dmc1_clk; | 28 | static struct clk *dmc1_clk; |
| 29 | static struct cpufreq_freqs freqs; | ||
| 30 | static DEFINE_MUTEX(set_freq_lock); | 29 | static DEFINE_MUTEX(set_freq_lock); |
| 31 | 30 | ||
| 32 | /* APLL M,P,S values for 1G/800Mhz */ | 31 | /* APLL M,P,S values for 1G/800Mhz */ |
| @@ -179,6 +178,7 @@ static int s5pv210_target(struct cpufreq_policy *policy, unsigned int index) | |||
| 179 | unsigned int priv_index; | 178 | unsigned int priv_index; |
| 180 | unsigned int pll_changing = 0; | 179 | unsigned int pll_changing = 0; |
| 181 | unsigned int bus_speed_changing = 0; | 180 | unsigned int bus_speed_changing = 0; |
| 181 | unsigned int old_freq, new_freq; | ||
| 182 | int arm_volt, int_volt; | 182 | int arm_volt, int_volt; |
| 183 | int ret = 0; | 183 | int ret = 0; |
| 184 | 184 | ||
| @@ -193,12 +193,12 @@ static int s5pv210_target(struct cpufreq_policy *policy, unsigned int index) | |||
| 193 | goto exit; | 193 | goto exit; |
| 194 | } | 194 | } |
| 195 | 195 | ||
| 196 | freqs.old = s5pv210_getspeed(0); | 196 | old_freq = s5pv210_getspeed(0); |
| 197 | freqs.new = s5pv210_freq_table[index].frequency; | 197 | new_freq = s5pv210_freq_table[index].frequency; |
| 198 | 198 | ||
| 199 | /* Finding current running level index */ | 199 | /* Finding current running level index */ |
| 200 | if (cpufreq_frequency_table_target(policy, s5pv210_freq_table, | 200 | if (cpufreq_frequency_table_target(policy, s5pv210_freq_table, |
| 201 | freqs.old, CPUFREQ_RELATION_H, | 201 | old_freq, CPUFREQ_RELATION_H, |
| 202 | &priv_index)) { | 202 | &priv_index)) { |
| 203 | ret = -EINVAL; | 203 | ret = -EINVAL; |
| 204 | goto exit; | 204 | goto exit; |
| @@ -207,7 +207,7 @@ static int s5pv210_target(struct cpufreq_policy *policy, unsigned int index) | |||
| 207 | arm_volt = dvs_conf[index].arm_volt; | 207 | arm_volt = dvs_conf[index].arm_volt; |
| 208 | int_volt = dvs_conf[index].int_volt; | 208 | int_volt = dvs_conf[index].int_volt; |
| 209 | 209 | ||
| 210 | if (freqs.new > freqs.old) { | 210 | if (new_freq > old_freq) { |
| 211 | ret = regulator_set_voltage(arm_regulator, | 211 | ret = regulator_set_voltage(arm_regulator, |
| 212 | arm_volt, arm_volt_max); | 212 | arm_volt, arm_volt_max); |
| 213 | if (ret) | 213 | if (ret) |
| @@ -219,8 +219,6 @@ static int s5pv210_target(struct cpufreq_policy *policy, unsigned int index) | |||
| 219 | goto exit; | 219 | goto exit; |
| 220 | } | 220 | } |
| 221 | 221 | ||
| 222 | cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); | ||
| 223 | |||
| 224 | /* Check if there need to change PLL */ | 222 | /* Check if there need to change PLL */ |
| 225 | if ((index == L0) || (priv_index == L0)) | 223 | if ((index == L0) || (priv_index == L0)) |
| 226 | pll_changing = 1; | 224 | pll_changing = 1; |
| @@ -431,9 +429,7 @@ static int s5pv210_target(struct cpufreq_policy *policy, unsigned int index) | |||
| 431 | } | 429 | } |
| 432 | } | 430 | } |
| 433 | 431 | ||
| 434 | cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); | 432 | if (new_freq < old_freq) { |
| 435 | |||
| 436 | if (freqs.new < freqs.old) { | ||
| 437 | regulator_set_voltage(int_regulator, | 433 | regulator_set_voltage(int_regulator, |
| 438 | int_volt, int_volt_max); | 434 | int_volt, int_volt_max); |
| 439 | 435 | ||
diff --git a/drivers/cpufreq/sa1100-cpufreq.c b/drivers/cpufreq/sa1100-cpufreq.c index b0da1fe40b1d..623da742f8e7 100644 --- a/drivers/cpufreq/sa1100-cpufreq.c +++ b/drivers/cpufreq/sa1100-cpufreq.c | |||
| @@ -180,22 +180,17 @@ static void sa1100_update_dram_timings(int current_speed, int new_speed) | |||
| 180 | static int sa1100_target(struct cpufreq_policy *policy, unsigned int ppcr) | 180 | static int sa1100_target(struct cpufreq_policy *policy, unsigned int ppcr) |
| 181 | { | 181 | { |
| 182 | unsigned int cur = sa11x0_getspeed(0); | 182 | unsigned int cur = sa11x0_getspeed(0); |
| 183 | struct cpufreq_freqs freqs; | 183 | unsigned int new_freq; |
| 184 | 184 | ||
| 185 | freqs.old = cur; | 185 | new_freq = sa11x0_freq_table[ppcr].frequency; |
| 186 | freqs.new = sa11x0_freq_table[ppcr].frequency; | ||
| 187 | 186 | ||
| 188 | cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); | 187 | if (new_freq > cur) |
| 189 | 188 | sa1100_update_dram_timings(cur, new_freq); | |
| 190 | if (freqs.new > cur) | ||
| 191 | sa1100_update_dram_timings(cur, freqs.new); | ||
| 192 | 189 | ||
| 193 | PPCR = ppcr; | 190 | PPCR = ppcr; |
| 194 | 191 | ||
| 195 | if (freqs.new < cur) | 192 | if (new_freq < cur) |
| 196 | sa1100_update_dram_timings(cur, freqs.new); | 193 | sa1100_update_dram_timings(cur, new_freq); |
| 197 | |||
| 198 | cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); | ||
| 199 | 194 | ||
| 200 | return 0; | 195 | return 0; |
| 201 | } | 196 | } |
diff --git a/drivers/cpufreq/sa1110-cpufreq.c b/drivers/cpufreq/sa1110-cpufreq.c index 55b1818c3e49..2c2b2e601d13 100644 --- a/drivers/cpufreq/sa1110-cpufreq.c +++ b/drivers/cpufreq/sa1110-cpufreq.c | |||
| @@ -232,15 +232,11 @@ sdram_update_refresh(u_int cpu_khz, struct sdram_params *sdram) | |||
| 232 | static int sa1110_target(struct cpufreq_policy *policy, unsigned int ppcr) | 232 | static int sa1110_target(struct cpufreq_policy *policy, unsigned int ppcr) |
| 233 | { | 233 | { |
| 234 | struct sdram_params *sdram = &sdram_params; | 234 | struct sdram_params *sdram = &sdram_params; |
| 235 | struct cpufreq_freqs freqs; | ||
| 236 | struct sdram_info sd; | 235 | struct sdram_info sd; |
| 237 | unsigned long flags; | 236 | unsigned long flags; |
| 238 | unsigned int unused; | 237 | unsigned int unused; |
| 239 | 238 | ||
| 240 | freqs.old = sa11x0_getspeed(0); | 239 | sdram_calculate_timing(&sd, sa11x0_freq_table[ppcr].frequency, sdram); |
| 241 | freqs.new = sa11x0_freq_table[ppcr].frequency; | ||
| 242 | |||
| 243 | sdram_calculate_timing(&sd, freqs.new, sdram); | ||
| 244 | 240 | ||
| 245 | #if 0 | 241 | #if 0 |
| 246 | /* | 242 | /* |
| @@ -259,8 +255,6 @@ static int sa1110_target(struct cpufreq_policy *policy, unsigned int ppcr) | |||
| 259 | sd.mdcas[2] = 0xaaaaaaaa; | 255 | sd.mdcas[2] = 0xaaaaaaaa; |
| 260 | #endif | 256 | #endif |
| 261 | 257 | ||
| 262 | cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); | ||
| 263 | |||
| 264 | /* | 258 | /* |
| 265 | * The clock could be going away for some time. Set the SDRAMs | 259 | * The clock could be going away for some time. Set the SDRAMs |
| 266 | * to refresh rapidly (every 64 memory clock cycles). To get | 260 | * to refresh rapidly (every 64 memory clock cycles). To get |
| @@ -305,9 +299,7 @@ static int sa1110_target(struct cpufreq_policy *policy, unsigned int ppcr) | |||
| 305 | /* | 299 | /* |
| 306 | * Now, return the SDRAM refresh back to normal. | 300 | * Now, return the SDRAM refresh back to normal. |
| 307 | */ | 301 | */ |
| 308 | sdram_update_refresh(freqs.new, sdram); | 302 | sdram_update_refresh(sa11x0_freq_table[ppcr].frequency, sdram); |
| 309 | |||
| 310 | cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); | ||
| 311 | 303 | ||
| 312 | return 0; | 304 | return 0; |
| 313 | } | 305 | } |
diff --git a/drivers/cpufreq/sc520_freq.c b/drivers/cpufreq/sc520_freq.c index 6c86452e1737..6adb354e359c 100644 --- a/drivers/cpufreq/sc520_freq.c +++ b/drivers/cpufreq/sc520_freq.c | |||
| @@ -56,17 +56,8 @@ static unsigned int sc520_freq_get_cpu_frequency(unsigned int cpu) | |||
| 56 | static int sc520_freq_target(struct cpufreq_policy *policy, unsigned int state) | 56 | static int sc520_freq_target(struct cpufreq_policy *policy, unsigned int state) |
| 57 | { | 57 | { |
| 58 | 58 | ||
| 59 | struct cpufreq_freqs freqs; | ||
| 60 | u8 clockspeed_reg; | 59 | u8 clockspeed_reg; |
| 61 | 60 | ||
| 62 | freqs.old = sc520_freq_get_cpu_frequency(0); | ||
| 63 | freqs.new = sc520_freq_table[state].frequency; | ||
| 64 | |||
| 65 | cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); | ||
| 66 | |||
| 67 | pr_debug("attempting to set frequency to %i kHz\n", | ||
| 68 | sc520_freq_table[state].frequency); | ||
| 69 | |||
| 70 | local_irq_disable(); | 61 | local_irq_disable(); |
| 71 | 62 | ||
| 72 | clockspeed_reg = *cpuctl & ~0x03; | 63 | clockspeed_reg = *cpuctl & ~0x03; |
| @@ -74,8 +65,6 @@ static int sc520_freq_target(struct cpufreq_policy *policy, unsigned int state) | |||
| 74 | 65 | ||
| 75 | local_irq_enable(); | 66 | local_irq_enable(); |
| 76 | 67 | ||
| 77 | cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); | ||
| 78 | |||
| 79 | return 0; | 68 | return 0; |
| 80 | } | 69 | } |
| 81 | 70 | ||
diff --git a/drivers/cpufreq/sparc-us2e-cpufreq.c b/drivers/cpufreq/sparc-us2e-cpufreq.c index 3bf5b8f03661..62aa23e219d4 100644 --- a/drivers/cpufreq/sparc-us2e-cpufreq.c +++ b/drivers/cpufreq/sparc-us2e-cpufreq.c | |||
| @@ -251,7 +251,6 @@ static int us2e_freq_target(struct cpufreq_policy *policy, unsigned int index) | |||
| 251 | unsigned long new_bits, new_freq; | 251 | unsigned long new_bits, new_freq; |
| 252 | unsigned long clock_tick, divisor, old_divisor, estar; | 252 | unsigned long clock_tick, divisor, old_divisor, estar; |
| 253 | cpumask_t cpus_allowed; | 253 | cpumask_t cpus_allowed; |
| 254 | struct cpufreq_freqs freqs; | ||
| 255 | 254 | ||
| 256 | cpumask_copy(&cpus_allowed, tsk_cpus_allowed(current)); | 255 | cpumask_copy(&cpus_allowed, tsk_cpus_allowed(current)); |
| 257 | set_cpus_allowed_ptr(current, cpumask_of(cpu)); | 256 | set_cpus_allowed_ptr(current, cpumask_of(cpu)); |
| @@ -265,16 +264,10 @@ static int us2e_freq_target(struct cpufreq_policy *policy, unsigned int index) | |||
| 265 | 264 | ||
| 266 | old_divisor = estar_to_divisor(estar); | 265 | old_divisor = estar_to_divisor(estar); |
| 267 | 266 | ||
| 268 | freqs.old = clock_tick / old_divisor; | ||
| 269 | freqs.new = new_freq; | ||
| 270 | cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); | ||
| 271 | |||
| 272 | if (old_divisor != divisor) | 267 | if (old_divisor != divisor) |
| 273 | us2e_transition(estar, new_bits, clock_tick * 1000, | 268 | us2e_transition(estar, new_bits, clock_tick * 1000, |
| 274 | old_divisor, divisor); | 269 | old_divisor, divisor); |
| 275 | 270 | ||
| 276 | cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); | ||
| 277 | |||
| 278 | set_cpus_allowed_ptr(current, &cpus_allowed); | 271 | set_cpus_allowed_ptr(current, &cpus_allowed); |
| 279 | 272 | ||
| 280 | return 0; | 273 | return 0; |
diff --git a/drivers/cpufreq/sparc-us3-cpufreq.c b/drivers/cpufreq/sparc-us3-cpufreq.c index 2e54d55915df..724ffbd7105d 100644 --- a/drivers/cpufreq/sparc-us3-cpufreq.c +++ b/drivers/cpufreq/sparc-us3-cpufreq.c | |||
| @@ -98,7 +98,6 @@ static int us3_freq_target(struct cpufreq_policy *policy, unsigned int index) | |||
| 98 | unsigned int cpu = policy->cpu; | 98 | unsigned int cpu = policy->cpu; |
| 99 | unsigned long new_bits, new_freq, reg; | 99 | unsigned long new_bits, new_freq, reg; |
| 100 | cpumask_t cpus_allowed; | 100 | cpumask_t cpus_allowed; |
| 101 | struct cpufreq_freqs freqs; | ||
| 102 | 101 | ||
| 103 | cpumask_copy(&cpus_allowed, tsk_cpus_allowed(current)); | 102 | cpumask_copy(&cpus_allowed, tsk_cpus_allowed(current)); |
| 104 | set_cpus_allowed_ptr(current, cpumask_of(cpu)); | 103 | set_cpus_allowed_ptr(current, cpumask_of(cpu)); |
| @@ -124,16 +123,10 @@ static int us3_freq_target(struct cpufreq_policy *policy, unsigned int index) | |||
| 124 | 123 | ||
| 125 | reg = read_safari_cfg(); | 124 | reg = read_safari_cfg(); |
| 126 | 125 | ||
| 127 | freqs.old = get_current_freq(cpu, reg); | ||
| 128 | freqs.new = new_freq; | ||
| 129 | cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); | ||
| 130 | |||
| 131 | reg &= ~SAFARI_CFG_DIV_MASK; | 126 | reg &= ~SAFARI_CFG_DIV_MASK; |
| 132 | reg |= new_bits; | 127 | reg |= new_bits; |
| 133 | write_safari_cfg(reg); | 128 | write_safari_cfg(reg); |
| 134 | 129 | ||
| 135 | cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); | ||
| 136 | |||
| 137 | set_cpus_allowed_ptr(current, &cpus_allowed); | 130 | set_cpus_allowed_ptr(current, &cpus_allowed); |
| 138 | 131 | ||
| 139 | return 0; | 132 | return 0; |
diff --git a/drivers/cpufreq/spear-cpufreq.c b/drivers/cpufreq/spear-cpufreq.c index 11a65be3fd76..d02ccd19c9c4 100644 --- a/drivers/cpufreq/spear-cpufreq.c +++ b/drivers/cpufreq/spear-cpufreq.c | |||
| @@ -107,12 +107,10 @@ static int spear1340_set_cpu_rate(struct clk *sys_pclk, unsigned long newfreq) | |||
| 107 | static int spear_cpufreq_target(struct cpufreq_policy *policy, | 107 | static int spear_cpufreq_target(struct cpufreq_policy *policy, |
| 108 | unsigned int index) | 108 | unsigned int index) |
| 109 | { | 109 | { |
| 110 | struct cpufreq_freqs freqs; | ||
| 111 | long newfreq; | 110 | long newfreq; |
| 112 | struct clk *srcclk; | 111 | struct clk *srcclk; |
| 113 | int ret, mult = 1; | 112 | int ret, mult = 1; |
| 114 | 113 | ||
| 115 | freqs.old = spear_cpufreq_get(0); | ||
| 116 | newfreq = spear_cpufreq.freq_tbl[index].frequency * 1000; | 114 | newfreq = spear_cpufreq.freq_tbl[index].frequency * 1000; |
| 117 | 115 | ||
| 118 | if (of_machine_is_compatible("st,spear1340")) { | 116 | if (of_machine_is_compatible("st,spear1340")) { |
| @@ -145,23 +143,14 @@ static int spear_cpufreq_target(struct cpufreq_policy *policy, | |||
| 145 | return newfreq; | 143 | return newfreq; |
| 146 | } | 144 | } |
| 147 | 145 | ||
| 148 | freqs.new = newfreq / 1000; | ||
| 149 | freqs.new /= mult; | ||
| 150 | |||
| 151 | cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); | ||
| 152 | |||
| 153 | if (mult == 2) | 146 | if (mult == 2) |
| 154 | ret = spear1340_set_cpu_rate(srcclk, newfreq); | 147 | ret = spear1340_set_cpu_rate(srcclk, newfreq); |
| 155 | else | 148 | else |
| 156 | ret = clk_set_rate(spear_cpufreq.clk, newfreq); | 149 | ret = clk_set_rate(spear_cpufreq.clk, newfreq); |
| 157 | 150 | ||
| 158 | /* Get current rate after clk_set_rate, in case of failure */ | 151 | if (ret) |
| 159 | if (ret) { | ||
| 160 | pr_err("CPU Freq: cpu clk_set_rate failed: %d\n", ret); | 152 | pr_err("CPU Freq: cpu clk_set_rate failed: %d\n", ret); |
| 161 | freqs.new = clk_get_rate(spear_cpufreq.clk) / 1000; | ||
| 162 | } | ||
| 163 | 153 | ||
| 164 | cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); | ||
| 165 | return ret; | 154 | return ret; |
| 166 | } | 155 | } |
| 167 | 156 | ||
diff --git a/drivers/cpufreq/speedstep-centrino.c b/drivers/cpufreq/speedstep-centrino.c index c51ec8c0e3a8..4e1daca5ce3b 100644 --- a/drivers/cpufreq/speedstep-centrino.c +++ b/drivers/cpufreq/speedstep-centrino.c | |||
| @@ -423,9 +423,8 @@ static int centrino_cpu_exit(struct cpufreq_policy *policy) | |||
| 423 | static int centrino_target(struct cpufreq_policy *policy, unsigned int index) | 423 | static int centrino_target(struct cpufreq_policy *policy, unsigned int index) |
| 424 | { | 424 | { |
| 425 | unsigned int msr, oldmsr = 0, h = 0, cpu = policy->cpu; | 425 | unsigned int msr, oldmsr = 0, h = 0, cpu = policy->cpu; |
| 426 | struct cpufreq_freqs freqs; | ||
| 427 | int retval = 0; | 426 | int retval = 0; |
| 428 | unsigned int j, first_cpu, tmp; | 427 | unsigned int j, first_cpu; |
| 429 | struct cpufreq_frequency_table *op_points; | 428 | struct cpufreq_frequency_table *op_points; |
| 430 | cpumask_var_t covered_cpus; | 429 | cpumask_var_t covered_cpus; |
| 431 | 430 | ||
| @@ -473,16 +472,6 @@ static int centrino_target(struct cpufreq_policy *policy, unsigned int index) | |||
| 473 | goto out; | 472 | goto out; |
| 474 | } | 473 | } |
| 475 | 474 | ||
| 476 | freqs.old = extract_clock(oldmsr, cpu, 0); | ||
| 477 | freqs.new = extract_clock(msr, cpu, 0); | ||
| 478 | |||
| 479 | pr_debug("target=%dkHz old=%d new=%d msr=%04x\n", | ||
| 480 | op_points->frequency, freqs.old, freqs.new, | ||
| 481 | msr); | ||
| 482 | |||
| 483 | cpufreq_notify_transition(policy, &freqs, | ||
| 484 | CPUFREQ_PRECHANGE); | ||
| 485 | |||
| 486 | first_cpu = 0; | 475 | first_cpu = 0; |
| 487 | /* all but 16 LSB are reserved, treat them with care */ | 476 | /* all but 16 LSB are reserved, treat them with care */ |
| 488 | oldmsr &= ~0xffff; | 477 | oldmsr &= ~0xffff; |
| @@ -497,8 +486,6 @@ static int centrino_target(struct cpufreq_policy *policy, unsigned int index) | |||
| 497 | cpumask_set_cpu(j, covered_cpus); | 486 | cpumask_set_cpu(j, covered_cpus); |
| 498 | } | 487 | } |
| 499 | 488 | ||
| 500 | cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); | ||
| 501 | |||
| 502 | if (unlikely(retval)) { | 489 | if (unlikely(retval)) { |
| 503 | /* | 490 | /* |
| 504 | * We have failed halfway through the frequency change. | 491 | * We have failed halfway through the frequency change. |
| @@ -509,12 +496,6 @@ static int centrino_target(struct cpufreq_policy *policy, unsigned int index) | |||
| 509 | 496 | ||
| 510 | for_each_cpu(j, covered_cpus) | 497 | for_each_cpu(j, covered_cpus) |
| 511 | wrmsr_on_cpu(j, MSR_IA32_PERF_CTL, oldmsr, h); | 498 | wrmsr_on_cpu(j, MSR_IA32_PERF_CTL, oldmsr, h); |
| 512 | |||
| 513 | tmp = freqs.new; | ||
| 514 | freqs.new = freqs.old; | ||
| 515 | freqs.old = tmp; | ||
| 516 | cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); | ||
| 517 | cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); | ||
| 518 | } | 499 | } |
| 519 | retval = 0; | 500 | retval = 0; |
| 520 | 501 | ||
diff --git a/drivers/cpufreq/speedstep-ich.c b/drivers/cpufreq/speedstep-ich.c index 707721ebb853..7639b2be2a90 100644 --- a/drivers/cpufreq/speedstep-ich.c +++ b/drivers/cpufreq/speedstep-ich.c | |||
| @@ -258,21 +258,12 @@ static unsigned int speedstep_get(unsigned int cpu) | |||
| 258 | static int speedstep_target(struct cpufreq_policy *policy, unsigned int index) | 258 | static int speedstep_target(struct cpufreq_policy *policy, unsigned int index) |
| 259 | { | 259 | { |
| 260 | unsigned int policy_cpu; | 260 | unsigned int policy_cpu; |
| 261 | struct cpufreq_freqs freqs; | ||
| 262 | 261 | ||
| 263 | policy_cpu = cpumask_any_and(policy->cpus, cpu_online_mask); | 262 | policy_cpu = cpumask_any_and(policy->cpus, cpu_online_mask); |
| 264 | freqs.old = speedstep_get(policy_cpu); | ||
| 265 | freqs.new = speedstep_freqs[index].frequency; | ||
| 266 | |||
| 267 | pr_debug("transiting from %u to %u kHz\n", freqs.old, freqs.new); | ||
| 268 | |||
| 269 | cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); | ||
| 270 | 263 | ||
| 271 | smp_call_function_single(policy_cpu, _speedstep_set_state, &index, | 264 | smp_call_function_single(policy_cpu, _speedstep_set_state, &index, |
| 272 | true); | 265 | true); |
| 273 | 266 | ||
| 274 | cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); | ||
| 275 | |||
| 276 | return 0; | 267 | return 0; |
| 277 | } | 268 | } |
| 278 | 269 | ||
diff --git a/drivers/cpufreq/speedstep-smi.c b/drivers/cpufreq/speedstep-smi.c index 19446e479ccc..0f5326d6f79f 100644 --- a/drivers/cpufreq/speedstep-smi.c +++ b/drivers/cpufreq/speedstep-smi.c | |||
| @@ -241,14 +241,7 @@ static void speedstep_set_state(unsigned int state) | |||
| 241 | */ | 241 | */ |
| 242 | static int speedstep_target(struct cpufreq_policy *policy, unsigned int index) | 242 | static int speedstep_target(struct cpufreq_policy *policy, unsigned int index) |
| 243 | { | 243 | { |
| 244 | struct cpufreq_freqs freqs; | ||
| 245 | |||
| 246 | freqs.old = speedstep_freqs[speedstep_get_state()].frequency; | ||
| 247 | freqs.new = speedstep_freqs[index].frequency; | ||
| 248 | |||
| 249 | cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); | ||
| 250 | speedstep_set_state(index); | 244 | speedstep_set_state(index); |
| 251 | cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); | ||
| 252 | 245 | ||
| 253 | return 0; | 246 | return 0; |
| 254 | } | 247 | } |
diff --git a/drivers/cpufreq/tegra-cpufreq.c b/drivers/cpufreq/tegra-cpufreq.c index bd7d89c013a5..f42df7ec03c5 100644 --- a/drivers/cpufreq/tegra-cpufreq.c +++ b/drivers/cpufreq/tegra-cpufreq.c | |||
| @@ -102,12 +102,8 @@ static int tegra_update_cpu_speed(struct cpufreq_policy *policy, | |||
| 102 | unsigned long rate) | 102 | unsigned long rate) |
| 103 | { | 103 | { |
| 104 | int ret = 0; | 104 | int ret = 0; |
| 105 | struct cpufreq_freqs freqs; | ||
| 106 | 105 | ||
| 107 | freqs.old = tegra_getspeed(0); | 106 | if (tegra_getspeed(0) == rate) |
| 108 | freqs.new = rate; | ||
| 109 | |||
| 110 | if (freqs.old == freqs.new) | ||
| 111 | return ret; | 107 | return ret; |
| 112 | 108 | ||
| 113 | /* | 109 | /* |
| @@ -121,21 +117,10 @@ static int tegra_update_cpu_speed(struct cpufreq_policy *policy, | |||
| 121 | else | 117 | else |
| 122 | clk_set_rate(emc_clk, 100000000); /* emc 50Mhz */ | 118 | clk_set_rate(emc_clk, 100000000); /* emc 50Mhz */ |
| 123 | 119 | ||
| 124 | cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); | 120 | ret = tegra_cpu_clk_set_rate(rate * 1000); |
| 125 | 121 | if (ret) | |
| 126 | #ifdef CONFIG_CPU_FREQ_DEBUG | 122 | pr_err("cpu-tegra: Failed to set cpu frequency to %lu kHz\n", |
| 127 | printk(KERN_DEBUG "cpufreq-tegra: transition: %u --> %u\n", | 123 | rate); |
| 128 | freqs.old, freqs.new); | ||
| 129 | #endif | ||
| 130 | |||
| 131 | ret = tegra_cpu_clk_set_rate(freqs.new * 1000); | ||
| 132 | if (ret) { | ||
| 133 | pr_err("cpu-tegra: Failed to set cpu frequency to %d kHz\n", | ||
| 134 | freqs.new); | ||
| 135 | freqs.new = freqs.old; | ||
| 136 | } | ||
| 137 | |||
| 138 | cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); | ||
| 139 | 124 | ||
| 140 | return ret; | 125 | return ret; |
| 141 | } | 126 | } |
diff --git a/drivers/cpufreq/vexpress-spc-cpufreq.c b/drivers/cpufreq/vexpress-spc-cpufreq.c new file mode 100644 index 000000000000..7f7c9c01b44e --- /dev/null +++ b/drivers/cpufreq/vexpress-spc-cpufreq.c | |||
| @@ -0,0 +1,70 @@ | |||
| 1 | /* | ||
| 2 | * Versatile Express SPC CPUFreq Interface driver | ||
| 3 | * | ||
| 4 | * It provides necessary ops to arm_big_little cpufreq driver. | ||
| 5 | * | ||
| 6 | * Copyright (C) 2013 ARM Ltd. | ||
| 7 | * Sudeep KarkadaNagesha <sudeep.karkadanagesha@arm.com> | ||
| 8 | * | ||
| 9 | * This program is free software; you can redistribute it and/or modify | ||
| 10 | * it under the terms of the GNU General Public License version 2 as | ||
| 11 | * published by the Free Software Foundation. | ||
| 12 | * | ||
| 13 | * This program is distributed "as is" WITHOUT ANY WARRANTY of any | ||
| 14 | * kind, whether express or implied; without even the implied warranty | ||
| 15 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 16 | * GNU General Public License for more details. | ||
| 17 | */ | ||
| 18 | |||
| 19 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
| 20 | |||
| 21 | #include <linux/cpufreq.h> | ||
| 22 | #include <linux/module.h> | ||
| 23 | #include <linux/platform_device.h> | ||
| 24 | #include <linux/pm_opp.h> | ||
| 25 | #include <linux/types.h> | ||
| 26 | |||
| 27 | #include "arm_big_little.h" | ||
| 28 | |||
| 29 | static int ve_spc_init_opp_table(struct device *cpu_dev) | ||
| 30 | { | ||
| 31 | /* | ||
| 32 | * platform specific SPC code must initialise the opp table | ||
| 33 | * so just check if the OPP count is non-zero | ||
| 34 | */ | ||
| 35 | return dev_pm_opp_get_opp_count(cpu_dev) <= 0; | ||
| 36 | } | ||
| 37 | |||
| 38 | static int ve_spc_get_transition_latency(struct device *cpu_dev) | ||
| 39 | { | ||
| 40 | return 1000000; /* 1 ms */ | ||
| 41 | } | ||
| 42 | |||
| 43 | static struct cpufreq_arm_bL_ops ve_spc_cpufreq_ops = { | ||
| 44 | .name = "vexpress-spc", | ||
| 45 | .get_transition_latency = ve_spc_get_transition_latency, | ||
| 46 | .init_opp_table = ve_spc_init_opp_table, | ||
| 47 | }; | ||
| 48 | |||
| 49 | static int ve_spc_cpufreq_probe(struct platform_device *pdev) | ||
| 50 | { | ||
| 51 | return bL_cpufreq_register(&ve_spc_cpufreq_ops); | ||
| 52 | } | ||
| 53 | |||
| 54 | static int ve_spc_cpufreq_remove(struct platform_device *pdev) | ||
| 55 | { | ||
| 56 | bL_cpufreq_unregister(&ve_spc_cpufreq_ops); | ||
| 57 | return 0; | ||
| 58 | } | ||
| 59 | |||
| 60 | static struct platform_driver ve_spc_cpufreq_platdrv = { | ||
| 61 | .driver = { | ||
| 62 | .name = "vexpress-spc-cpufreq", | ||
| 63 | .owner = THIS_MODULE, | ||
| 64 | }, | ||
| 65 | .probe = ve_spc_cpufreq_probe, | ||
| 66 | .remove = ve_spc_cpufreq_remove, | ||
| 67 | }; | ||
| 68 | module_platform_driver(ve_spc_cpufreq_platdrv); | ||
| 69 | |||
| 70 | MODULE_LICENSE("GPL"); | ||
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index 93a8c34d6c7f..5bd6ab9b0c27 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h | |||
| @@ -237,6 +237,13 @@ struct cpufreq_driver { | |||
| 237 | */ | 237 | */ |
| 238 | #define CPUFREQ_HAVE_GOVERNOR_PER_POLICY (1 << 3) | 238 | #define CPUFREQ_HAVE_GOVERNOR_PER_POLICY (1 << 3) |
| 239 | 239 | ||
| 240 | /* | ||
| 241 | * Driver will do POSTCHANGE notifications from outside of their ->target() | ||
| 242 | * routine and so must set cpufreq_driver->flags with this flag, so that core | ||
| 243 | * can handle them specially. | ||
| 244 | */ | ||
| 245 | #define CPUFREQ_ASYNC_NOTIFICATION (1 << 4) | ||
| 246 | |||
| 240 | int cpufreq_register_driver(struct cpufreq_driver *driver_data); | 247 | int cpufreq_register_driver(struct cpufreq_driver *driver_data); |
| 241 | int cpufreq_unregister_driver(struct cpufreq_driver *driver_data); | 248 | int cpufreq_unregister_driver(struct cpufreq_driver *driver_data); |
| 242 | 249 | ||
