aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-shmobile/pm-sh7372.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-10-02 21:32:35 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2012-10-02 21:32:35 -0400
commit16642a2e7be23bbda013fc32d8f6c68982eab603 (patch)
tree346ae485f485f6901e5d8150f0d34d178a7dd448 /arch/arm/mach-shmobile/pm-sh7372.c
parent51562cba98939da0a1d10fe7c25359b77a069033 (diff)
parentb9142167a2bb979b58b98ffcd928a311b55cbd9f (diff)
Merge tag 'pm-for-3.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
Pull power management updates from Rafael J Wysocki: - Improved system suspend/resume and runtime PM handling for the SH TMU, CMT and MTU2 clock event devices (also used by ARM/shmobile). - Generic PM domains framework extensions related to cpuidle support and domain objects lookup using names. - ARM/shmobile power management updates including improved support for the SH7372's A4S power domain containing the CPU core. - cpufreq changes related to AMD CPUs support from Matthew Garrett, Andre Przywara and Borislav Petkov. - cpu0 cpufreq driver from Shawn Guo. - cpufreq governor fixes related to the relaxing of limit from Michal Pecio. - OMAP cpufreq updates from Axel Lin and Richard Zhao. - cpuidle ladder governor fixes related to the disabling of states from Carsten Emde and me. - Runtime PM core updates related to the interactions with the system suspend core from Alan Stern and Kevin Hilman. - Wakeup sources modification allowing more helper functions to be called from interrupt context from John Stultz and additional diagnostic code from Todd Poynor. - System suspend error code path fix from Feng Hong. Fixed up conflicts in cpufreq/powernow-k8 that stemmed from the workqueue fixes conflicting fairly badly with the removal of support for hardware P-state chips. The changes were independent but somewhat intertwined. * tag 'pm-for-3.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: (76 commits) Revert "PM QoS: Use spinlock in the per-device PM QoS constraints code" PM / Runtime: let rpm_resume() succeed if RPM_ACTIVE, even when disabled, v2 cpuidle: rename function name "__cpuidle_register_driver", v2 cpufreq: OMAP: Check IS_ERR() instead of NULL for omap_device_get_by_hwmod_name cpuidle: remove some empty lines PM: Prevent runtime suspend during system resume PM QoS: Use spinlock in the per-device PM QoS constraints code PM / Sleep: use resume event when call dpm_resume_early cpuidle / ACPI : move cpuidle_device field out of the acpi_processor_power structure ACPI / processor: remove pointless variable initialization ACPI / processor: remove unused function parameter cpufreq: OMAP: remove loops_per_jiffy recalculate for smp sections: fix section conflicts in drivers/cpufreq cpufreq: conservative: update frequency when limits are relaxed cpufreq / ondemand: update frequency when limits are relaxed properly __init-annotate pm_sysrq_init() cpufreq: Add a generic cpufreq-cpu0 driver PM / OPP: Initialize OPP table from device tree ARM: add cpufreq transiton notifier to adjust loops_per_jiffy for smp cpufreq: Remove support for hardware P-state chips from powernow-k8 ...
Diffstat (limited to 'arch/arm/mach-shmobile/pm-sh7372.c')
-rw-r--r--arch/arm/mach-shmobile/pm-sh7372.c283
1 files changed, 181 insertions, 102 deletions
diff --git a/arch/arm/mach-shmobile/pm-sh7372.c b/arch/arm/mach-shmobile/pm-sh7372.c
index 162121842a2b..a0826a48dd08 100644
--- a/arch/arm/mach-shmobile/pm-sh7372.c
+++ b/arch/arm/mach-shmobile/pm-sh7372.c
@@ -21,6 +21,7 @@
21#include <linux/irq.h> 21#include <linux/irq.h>
22#include <linux/bitrev.h> 22#include <linux/bitrev.h>
23#include <linux/console.h> 23#include <linux/console.h>
24#include <asm/cpuidle.h>
24#include <asm/io.h> 25#include <asm/io.h>
25#include <asm/tlbflush.h> 26#include <asm/tlbflush.h>
26#include <asm/suspend.h> 27#include <asm/suspend.h>
@@ -72,20 +73,7 @@
72 73
73#ifdef CONFIG_PM 74#ifdef CONFIG_PM
74 75
75struct rmobile_pm_domain sh7372_pd_a4lc = { 76#define PM_DOMAIN_ON_OFF_LATENCY_NS 250000
76 .genpd.name = "A4LC",
77 .bit_shift = 1,
78};
79
80struct rmobile_pm_domain sh7372_pd_a4mp = {
81 .genpd.name = "A4MP",
82 .bit_shift = 2,
83};
84
85struct rmobile_pm_domain sh7372_pd_d4 = {
86 .genpd.name = "D4",
87 .bit_shift = 3,
88};
89 77
90static int sh7372_a4r_pd_suspend(void) 78static int sh7372_a4r_pd_suspend(void)
91{ 79{
@@ -94,39 +82,25 @@ static int sh7372_a4r_pd_suspend(void)
94 return 0; 82 return 0;
95} 83}
96 84
97struct rmobile_pm_domain sh7372_pd_a4r = { 85static bool a4s_suspend_ready;
98 .genpd.name = "A4R",
99 .bit_shift = 5,
100 .suspend = sh7372_a4r_pd_suspend,
101 .resume = sh7372_intcs_resume,
102};
103 86
104struct rmobile_pm_domain sh7372_pd_a3rv = { 87static int sh7372_a4s_pd_suspend(void)
105 .genpd.name = "A3RV",
106 .bit_shift = 6,
107};
108
109struct rmobile_pm_domain sh7372_pd_a3ri = {
110 .genpd.name = "A3RI",
111 .bit_shift = 8,
112};
113
114static int sh7372_pd_a4s_suspend(void)
115{ 88{
116 /* 89 /*
117 * The A4S domain contains the CPU core and therefore it should 90 * The A4S domain contains the CPU core and therefore it should
118 * only be turned off if the CPU is in use. 91 * only be turned off if the CPU is not in use. This may happen
92 * during system suspend, when SYSC is going to be used for generating
93 * resume signals and a4s_suspend_ready is set to let
94 * sh7372_enter_suspend() know that it can turn A4S off.
119 */ 95 */
96 a4s_suspend_ready = true;
120 return -EBUSY; 97 return -EBUSY;
121} 98}
122 99
123struct rmobile_pm_domain sh7372_pd_a4s = { 100static void sh7372_a4s_pd_resume(void)
124 .genpd.name = "A4S", 101{
125 .bit_shift = 10, 102 a4s_suspend_ready = false;
126 .gov = &pm_domain_always_on_gov, 103}
127 .no_debug = true,
128 .suspend = sh7372_pd_a4s_suspend,
129};
130 104
131static int sh7372_a3sp_pd_suspend(void) 105static int sh7372_a3sp_pd_suspend(void)
132{ 106{
@@ -137,18 +111,80 @@ static int sh7372_a3sp_pd_suspend(void)
137 return console_suspend_enabled ? 0 : -EBUSY; 111 return console_suspend_enabled ? 0 : -EBUSY;
138} 112}
139 113
140struct rmobile_pm_domain sh7372_pd_a3sp = { 114static struct rmobile_pm_domain sh7372_pm_domains[] = {
141 .genpd.name = "A3SP", 115 {
142 .bit_shift = 11, 116 .genpd.name = "A4LC",
143 .gov = &pm_domain_always_on_gov, 117 .genpd.power_on_latency_ns = PM_DOMAIN_ON_OFF_LATENCY_NS,
144 .no_debug = true, 118 .genpd.power_off_latency_ns = PM_DOMAIN_ON_OFF_LATENCY_NS,
145 .suspend = sh7372_a3sp_pd_suspend, 119 .bit_shift = 1,
120 },
121 {
122 .genpd.name = "A4MP",
123 .genpd.power_on_latency_ns = PM_DOMAIN_ON_OFF_LATENCY_NS,
124 .genpd.power_off_latency_ns = PM_DOMAIN_ON_OFF_LATENCY_NS,
125 .bit_shift = 2,
126 },
127 {
128 .genpd.name = "D4",
129 .genpd.power_on_latency_ns = PM_DOMAIN_ON_OFF_LATENCY_NS,
130 .genpd.power_off_latency_ns = PM_DOMAIN_ON_OFF_LATENCY_NS,
131 .bit_shift = 3,
132 },
133 {
134 .genpd.name = "A4R",
135 .genpd.power_on_latency_ns = PM_DOMAIN_ON_OFF_LATENCY_NS,
136 .genpd.power_off_latency_ns = PM_DOMAIN_ON_OFF_LATENCY_NS,
137 .bit_shift = 5,
138 .suspend = sh7372_a4r_pd_suspend,
139 .resume = sh7372_intcs_resume,
140 },
141 {
142 .genpd.name = "A3RV",
143 .genpd.power_on_latency_ns = PM_DOMAIN_ON_OFF_LATENCY_NS,
144 .genpd.power_off_latency_ns = PM_DOMAIN_ON_OFF_LATENCY_NS,
145 .bit_shift = 6,
146 },
147 {
148 .genpd.name = "A3RI",
149 .genpd.power_on_latency_ns = PM_DOMAIN_ON_OFF_LATENCY_NS,
150 .genpd.power_off_latency_ns = PM_DOMAIN_ON_OFF_LATENCY_NS,
151 .bit_shift = 8,
152 },
153 {
154 .genpd.name = "A4S",
155 .genpd.power_on_latency_ns = PM_DOMAIN_ON_OFF_LATENCY_NS,
156 .genpd.power_off_latency_ns = PM_DOMAIN_ON_OFF_LATENCY_NS,
157 .bit_shift = 10,
158 .gov = &pm_domain_always_on_gov,
159 .no_debug = true,
160 .suspend = sh7372_a4s_pd_suspend,
161 .resume = sh7372_a4s_pd_resume,
162 },
163 {
164 .genpd.name = "A3SP",
165 .genpd.power_on_latency_ns = PM_DOMAIN_ON_OFF_LATENCY_NS,
166 .genpd.power_off_latency_ns = PM_DOMAIN_ON_OFF_LATENCY_NS,
167 .bit_shift = 11,
168 .gov = &pm_domain_always_on_gov,
169 .no_debug = true,
170 .suspend = sh7372_a3sp_pd_suspend,
171 },
172 {
173 .genpd.name = "A3SG",
174 .genpd.power_on_latency_ns = PM_DOMAIN_ON_OFF_LATENCY_NS,
175 .genpd.power_off_latency_ns = PM_DOMAIN_ON_OFF_LATENCY_NS,
176 .bit_shift = 13,
177 },
146}; 178};
147 179
148struct rmobile_pm_domain sh7372_pd_a3sg = { 180void __init sh7372_init_pm_domains(void)
149 .genpd.name = "A3SG", 181{
150 .bit_shift = 13, 182 rmobile_init_domains(sh7372_pm_domains, ARRAY_SIZE(sh7372_pm_domains));
151}; 183 pm_genpd_add_subdomain_names("A4LC", "A3RV");
184 pm_genpd_add_subdomain_names("A4R", "A4LC");
185 pm_genpd_add_subdomain_names("A4S", "A3SG");
186 pm_genpd_add_subdomain_names("A4S", "A3SP");
187}
152 188
153#endif /* CONFIG_PM */ 189#endif /* CONFIG_PM */
154 190
@@ -304,6 +340,21 @@ static void sh7372_enter_a3sm_common(int pllc0_on)
304 sh7372_set_reset_vector(__pa(sh7372_resume_core_standby_sysc)); 340 sh7372_set_reset_vector(__pa(sh7372_resume_core_standby_sysc));
305 sh7372_enter_sysc(pllc0_on, 1 << 12); 341 sh7372_enter_sysc(pllc0_on, 1 << 12);
306} 342}
343
344static void sh7372_enter_a4s_common(int pllc0_on)
345{
346 sh7372_intca_suspend();
347 sh7372_set_reset_vector(SMFRAM);
348 sh7372_enter_sysc(pllc0_on, 1 << 10);
349 sh7372_intca_resume();
350}
351
352static void sh7372_pm_setup_smfram(void)
353{
354 memcpy((void *)SMFRAM, sh7372_resume_core_standby_sysc, 0x100);
355}
356#else
357static inline void sh7372_pm_setup_smfram(void) {}
307#endif /* CONFIG_SUSPEND || CONFIG_CPU_IDLE */ 358#endif /* CONFIG_SUSPEND || CONFIG_CPU_IDLE */
308 359
309#ifdef CONFIG_CPU_IDLE 360#ifdef CONFIG_CPU_IDLE
@@ -313,7 +364,8 @@ static int sh7372_do_idle_core_standby(unsigned long unused)
313 return 0; 364 return 0;
314} 365}
315 366
316static void sh7372_enter_core_standby(void) 367static int sh7372_enter_core_standby(struct cpuidle_device *dev,
368 struct cpuidle_driver *drv, int index)
317{ 369{
318 sh7372_set_reset_vector(__pa(sh7372_resume_core_standby_sysc)); 370 sh7372_set_reset_vector(__pa(sh7372_resume_core_standby_sysc));
319 371
@@ -324,83 +376,102 @@ static void sh7372_enter_core_standby(void)
324 376
325 /* disable reset vector translation */ 377 /* disable reset vector translation */
326 __raw_writel(0, SBAR); 378 __raw_writel(0, SBAR);
379
380 return 1;
327} 381}
328 382
329static void sh7372_enter_a3sm_pll_on(void) 383static int sh7372_enter_a3sm_pll_on(struct cpuidle_device *dev,
384 struct cpuidle_driver *drv, int index)
330{ 385{
331 sh7372_enter_a3sm_common(1); 386 sh7372_enter_a3sm_common(1);
387 return 2;
332} 388}
333 389
334static void sh7372_enter_a3sm_pll_off(void) 390static int sh7372_enter_a3sm_pll_off(struct cpuidle_device *dev,
391 struct cpuidle_driver *drv, int index)
335{ 392{
336 sh7372_enter_a3sm_common(0); 393 sh7372_enter_a3sm_common(0);
394 return 3;
337} 395}
338 396
339static void sh7372_cpuidle_setup(struct cpuidle_driver *drv) 397static int sh7372_enter_a4s(struct cpuidle_device *dev,
398 struct cpuidle_driver *drv, int index)
340{ 399{
341 struct cpuidle_state *state = &drv->states[drv->state_count]; 400 unsigned long msk, msk2;
342 401
343 snprintf(state->name, CPUIDLE_NAME_LEN, "C2"); 402 if (!sh7372_sysc_valid(&msk, &msk2))
344 strncpy(state->desc, "Core Standby Mode", CPUIDLE_DESC_LEN); 403 return sh7372_enter_a3sm_pll_off(dev, drv, index);
345 state->exit_latency = 10; 404
346 state->target_residency = 20 + 10; 405 sh7372_setup_sysc(msk, msk2);
347 state->flags = CPUIDLE_FLAG_TIME_VALID; 406 sh7372_enter_a4s_common(0);
348 shmobile_cpuidle_modes[drv->state_count] = sh7372_enter_core_standby; 407 return 4;
349 drv->state_count++;
350
351 state = &drv->states[drv->state_count];
352 snprintf(state->name, CPUIDLE_NAME_LEN, "C3");
353 strncpy(state->desc, "A3SM PLL ON", CPUIDLE_DESC_LEN);
354 state->exit_latency = 20;
355 state->target_residency = 30 + 20;
356 state->flags = CPUIDLE_FLAG_TIME_VALID;
357 shmobile_cpuidle_modes[drv->state_count] = sh7372_enter_a3sm_pll_on;
358 drv->state_count++;
359
360 state = &drv->states[drv->state_count];
361 snprintf(state->name, CPUIDLE_NAME_LEN, "C4");
362 strncpy(state->desc, "A3SM PLL OFF", CPUIDLE_DESC_LEN);
363 state->exit_latency = 120;
364 state->target_residency = 30 + 120;
365 state->flags = CPUIDLE_FLAG_TIME_VALID;
366 shmobile_cpuidle_modes[drv->state_count] = sh7372_enter_a3sm_pll_off;
367 drv->state_count++;
368} 408}
369 409
410static struct cpuidle_driver sh7372_cpuidle_driver = {
411 .name = "sh7372_cpuidle",
412 .owner = THIS_MODULE,
413 .en_core_tk_irqen = 1,
414 .state_count = 5,
415 .safe_state_index = 0, /* C1 */
416 .states[0] = ARM_CPUIDLE_WFI_STATE,
417 .states[0].enter = shmobile_enter_wfi,
418 .states[1] = {
419 .name = "C2",
420 .desc = "Core Standby Mode",
421 .exit_latency = 10,
422 .target_residency = 20 + 10,
423 .flags = CPUIDLE_FLAG_TIME_VALID,
424 .enter = sh7372_enter_core_standby,
425 },
426 .states[2] = {
427 .name = "C3",
428 .desc = "A3SM PLL ON",
429 .exit_latency = 20,
430 .target_residency = 30 + 20,
431 .flags = CPUIDLE_FLAG_TIME_VALID,
432 .enter = sh7372_enter_a3sm_pll_on,
433 },
434 .states[3] = {
435 .name = "C4",
436 .desc = "A3SM PLL OFF",
437 .exit_latency = 120,
438 .target_residency = 30 + 120,
439 .flags = CPUIDLE_FLAG_TIME_VALID,
440 .enter = sh7372_enter_a3sm_pll_off,
441 },
442 .states[4] = {
443 .name = "C5",
444 .desc = "A4S PLL OFF",
445 .exit_latency = 240,
446 .target_residency = 30 + 240,
447 .flags = CPUIDLE_FLAG_TIME_VALID,
448 .enter = sh7372_enter_a4s,
449 .disabled = true,
450 },
451};
452
370static void sh7372_cpuidle_init(void) 453static void sh7372_cpuidle_init(void)
371{ 454{
372 shmobile_cpuidle_setup = sh7372_cpuidle_setup; 455 shmobile_cpuidle_set_driver(&sh7372_cpuidle_driver);
373} 456}
374#else 457#else
375static void sh7372_cpuidle_init(void) {} 458static void sh7372_cpuidle_init(void) {}
376#endif 459#endif
377 460
378#ifdef CONFIG_SUSPEND 461#ifdef CONFIG_SUSPEND
379static void sh7372_enter_a4s_common(int pllc0_on)
380{
381 sh7372_intca_suspend();
382 memcpy((void *)SMFRAM, sh7372_resume_core_standby_sysc, 0x100);
383 sh7372_set_reset_vector(SMFRAM);
384 sh7372_enter_sysc(pllc0_on, 1 << 10);
385 sh7372_intca_resume();
386}
387
388static int sh7372_enter_suspend(suspend_state_t suspend_state) 462static int sh7372_enter_suspend(suspend_state_t suspend_state)
389{ 463{
390 unsigned long msk, msk2; 464 unsigned long msk, msk2;
391 465
392 /* check active clocks to determine potential wakeup sources */ 466 /* check active clocks to determine potential wakeup sources */
393 if (sh7372_sysc_valid(&msk, &msk2)) { 467 if (sh7372_sysc_valid(&msk, &msk2) && a4s_suspend_ready) {
394 if (!console_suspend_enabled && 468 /* convert INTC mask/sense to SYSC mask/sense */
395 sh7372_pd_a4s.genpd.status == GPD_STATE_POWER_OFF) { 469 sh7372_setup_sysc(msk, msk2);
396 /* convert INTC mask/sense to SYSC mask/sense */ 470
397 sh7372_setup_sysc(msk, msk2); 471 /* enter A4S sleep with PLLC0 off */
398 472 pr_debug("entering A4S\n");
399 /* enter A4S sleep with PLLC0 off */ 473 sh7372_enter_a4s_common(0);
400 pr_debug("entering A4S\n"); 474 return 0;
401 sh7372_enter_a4s_common(0);
402 return 0;
403 }
404 } 475 }
405 476
406 /* default to enter A3SM sleep with PLLC0 off */ 477 /* default to enter A3SM sleep with PLLC0 off */
@@ -426,7 +497,7 @@ static int sh7372_pm_notifier_fn(struct notifier_block *notifier,
426 * executed during system suspend and resume, respectively, so 497 * executed during system suspend and resume, respectively, so
427 * that those functions don't crash while accessing the INTCS. 498 * that those functions don't crash while accessing the INTCS.
428 */ 499 */
429 pm_genpd_poweron(&sh7372_pd_a4r.genpd); 500 pm_genpd_name_poweron("A4R");
430 break; 501 break;
431 case PM_POST_SUSPEND: 502 case PM_POST_SUSPEND:
432 pm_genpd_poweroff_unused(); 503 pm_genpd_poweroff_unused();
@@ -455,6 +526,14 @@ void __init sh7372_pm_init(void)
455 /* do not convert A3SM, A3SP, A3SG, A4R power down into A4S */ 526 /* do not convert A3SM, A3SP, A3SG, A4R power down into A4S */
456 __raw_writel(0, PDNSEL); 527 __raw_writel(0, PDNSEL);
457 528
529 sh7372_pm_setup_smfram();
530
458 sh7372_suspend_init(); 531 sh7372_suspend_init();
459 sh7372_cpuidle_init(); 532 sh7372_cpuidle_init();
460} 533}
534
535void __init sh7372_pm_init_late(void)
536{
537 shmobile_init_late();
538 pm_genpd_name_attach_cpuidle("A4S", 4);
539}