aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-shmobile/pm-sh7372.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-01-08 16:10:57 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2012-01-08 16:10:57 -0500
commiteb59c505f8a5906ad2e053d14fab50eb8574fd6f (patch)
treec6e875adc12b481b916e847e8f80b8881a0fb02c /arch/arm/mach-shmobile/pm-sh7372.c
parent1619ed8f60959829d070d8f39cd2f8ca0e7135ce (diff)
parentc233523b3d392e530033a7587d7970dc62a02361 (diff)
Merge branch 'pm-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
* 'pm-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: (76 commits) PM / Hibernate: Implement compat_ioctl for /dev/snapshot PM / Freezer: fix return value of freezable_schedule_timeout_killable() PM / shmobile: Allow the A4R domain to be turned off at run time PM / input / touchscreen: Make st1232 use device PM QoS constraints PM / QoS: Introduce dev_pm_qos_add_ancestor_request() PM / shmobile: Remove the stay_on flag from SH7372's PM domains PM / shmobile: Don't include SH7372's INTCS in syscore suspend/resume PM / shmobile: Add support for the sh7372 A4S power domain / sleep mode PM: Drop generic_subsys_pm_ops PM / Sleep: Remove forward-only callbacks from AMBA bus type PM / Sleep: Remove forward-only callbacks from platform bus type PM: Run the driver callback directly if the subsystem one is not there PM / Sleep: Make pm_op() and pm_noirq_op() return callback pointers PM/Devfreq: Add Exynos4-bus device DVFS driver for Exynos4210/4212/4412. PM / Sleep: Merge internal functions in generic_ops.c PM / Sleep: Simplify generic system suspend callbacks PM / Hibernate: Remove deprecated hibernation snapshot ioctls PM / Sleep: Fix freezer failures due to racy usermodehelper_is_disabled() ARM: S3C64XX: Implement basic power domain support PM / shmobile: Use common always on power domain governor ... Fix up trivial conflict in fs/xfs/xfs_buf.c due to removal of unused XBT_FORCE_SLEEP bit
Diffstat (limited to 'arch/arm/mach-shmobile/pm-sh7372.c')
-rw-r--r--arch/arm/mach-shmobile/pm-sh7372.c196
1 files changed, 146 insertions, 50 deletions
diff --git a/arch/arm/mach-shmobile/pm-sh7372.c b/arch/arm/mach-shmobile/pm-sh7372.c
index 34bbcbfb1706..77b8fc12fc2f 100644
--- a/arch/arm/mach-shmobile/pm-sh7372.c
+++ b/arch/arm/mach-shmobile/pm-sh7372.c
@@ -82,11 +82,12 @@ static int pd_power_down(struct generic_pm_domain *genpd)
82 struct sh7372_pm_domain *sh7372_pd = to_sh7372_pd(genpd); 82 struct sh7372_pm_domain *sh7372_pd = to_sh7372_pd(genpd);
83 unsigned int mask = 1 << sh7372_pd->bit_shift; 83 unsigned int mask = 1 << sh7372_pd->bit_shift;
84 84
85 if (sh7372_pd->suspend) 85 if (sh7372_pd->suspend) {
86 sh7372_pd->suspend(); 86 int ret = sh7372_pd->suspend();
87 87
88 if (sh7372_pd->stay_on) 88 if (ret)
89 return 0; 89 return ret;
90 }
90 91
91 if (__raw_readl(PSTR) & mask) { 92 if (__raw_readl(PSTR) & mask) {
92 unsigned int retry_count; 93 unsigned int retry_count;
@@ -101,8 +102,8 @@ static int pd_power_down(struct generic_pm_domain *genpd)
101 } 102 }
102 103
103 if (!sh7372_pd->no_debug) 104 if (!sh7372_pd->no_debug)
104 pr_debug("sh7372 power domain down 0x%08x -> PSTR = 0x%08x\n", 105 pr_debug("%s: Power off, 0x%08x -> PSTR = 0x%08x\n",
105 mask, __raw_readl(PSTR)); 106 genpd->name, mask, __raw_readl(PSTR));
106 107
107 return 0; 108 return 0;
108} 109}
@@ -113,9 +114,6 @@ static int __pd_power_up(struct sh7372_pm_domain *sh7372_pd, bool do_resume)
113 unsigned int retry_count; 114 unsigned int retry_count;
114 int ret = 0; 115 int ret = 0;
115 116
116 if (sh7372_pd->stay_on)
117 goto out;
118
119 if (__raw_readl(PSTR) & mask) 117 if (__raw_readl(PSTR) & mask)
120 goto out; 118 goto out;
121 119
@@ -133,8 +131,8 @@ static int __pd_power_up(struct sh7372_pm_domain *sh7372_pd, bool do_resume)
133 ret = -EIO; 131 ret = -EIO;
134 132
135 if (!sh7372_pd->no_debug) 133 if (!sh7372_pd->no_debug)
136 pr_debug("sh7372 power domain up 0x%08x -> PSTR = 0x%08x\n", 134 pr_debug("%s: Power on, 0x%08x -> PSTR = 0x%08x\n",
137 mask, __raw_readl(PSTR)); 135 sh7372_pd->genpd.name, mask, __raw_readl(PSTR));
138 136
139 out: 137 out:
140 if (ret == 0 && sh7372_pd->resume && do_resume) 138 if (ret == 0 && sh7372_pd->resume && do_resume)
@@ -148,35 +146,60 @@ static int pd_power_up(struct generic_pm_domain *genpd)
148 return __pd_power_up(to_sh7372_pd(genpd), true); 146 return __pd_power_up(to_sh7372_pd(genpd), true);
149} 147}
150 148
151static void sh7372_a4r_suspend(void) 149static int sh7372_a4r_suspend(void)
152{ 150{
153 sh7372_intcs_suspend(); 151 sh7372_intcs_suspend();
154 __raw_writel(0x300fffff, WUPRMSK); /* avoid wakeup */ 152 __raw_writel(0x300fffff, WUPRMSK); /* avoid wakeup */
153 return 0;
155} 154}
156 155
157static bool pd_active_wakeup(struct device *dev) 156static bool pd_active_wakeup(struct device *dev)
158{ 157{
159 return true; 158 bool (*active_wakeup)(struct device *dev);
159
160 active_wakeup = dev_gpd_data(dev)->ops.active_wakeup;
161 return active_wakeup ? active_wakeup(dev) : true;
160} 162}
161 163
162static bool sh7372_power_down_forbidden(struct dev_pm_domain *domain) 164static int sh7372_stop_dev(struct device *dev)
163{ 165{
164 return false; 166 int (*stop)(struct device *dev);
167
168 stop = dev_gpd_data(dev)->ops.stop;
169 if (stop) {
170 int ret = stop(dev);
171 if (ret)
172 return ret;
173 }
174 return pm_clk_suspend(dev);
165} 175}
166 176
167struct dev_power_governor sh7372_always_on_gov = { 177static int sh7372_start_dev(struct device *dev)
168 .power_down_ok = sh7372_power_down_forbidden, 178{
169}; 179 int (*start)(struct device *dev);
180 int ret;
181
182 ret = pm_clk_resume(dev);
183 if (ret)
184 return ret;
185
186 start = dev_gpd_data(dev)->ops.start;
187 if (start)
188 ret = start(dev);
189
190 return ret;
191}
170 192
171void sh7372_init_pm_domain(struct sh7372_pm_domain *sh7372_pd) 193void sh7372_init_pm_domain(struct sh7372_pm_domain *sh7372_pd)
172{ 194{
173 struct generic_pm_domain *genpd = &sh7372_pd->genpd; 195 struct generic_pm_domain *genpd = &sh7372_pd->genpd;
196 struct dev_power_governor *gov = sh7372_pd->gov;
174 197
175 pm_genpd_init(genpd, sh7372_pd->gov, false); 198 pm_genpd_init(genpd, gov ? : &simple_qos_governor, false);
176 genpd->stop_device = pm_clk_suspend; 199 genpd->dev_ops.stop = sh7372_stop_dev;
177 genpd->start_device = pm_clk_resume; 200 genpd->dev_ops.start = sh7372_start_dev;
201 genpd->dev_ops.active_wakeup = pd_active_wakeup;
178 genpd->dev_irq_safe = true; 202 genpd->dev_irq_safe = true;
179 genpd->active_wakeup = pd_active_wakeup;
180 genpd->power_off = pd_power_down; 203 genpd->power_off = pd_power_down;
181 genpd->power_on = pd_power_up; 204 genpd->power_on = pd_power_up;
182 __pd_power_up(sh7372_pd, false); 205 __pd_power_up(sh7372_pd, false);
@@ -199,48 +222,73 @@ void sh7372_pm_add_subdomain(struct sh7372_pm_domain *sh7372_pd,
199} 222}
200 223
201struct sh7372_pm_domain sh7372_a4lc = { 224struct sh7372_pm_domain sh7372_a4lc = {
225 .genpd.name = "A4LC",
202 .bit_shift = 1, 226 .bit_shift = 1,
203}; 227};
204 228
205struct sh7372_pm_domain sh7372_a4mp = { 229struct sh7372_pm_domain sh7372_a4mp = {
230 .genpd.name = "A4MP",
206 .bit_shift = 2, 231 .bit_shift = 2,
207}; 232};
208 233
209struct sh7372_pm_domain sh7372_d4 = { 234struct sh7372_pm_domain sh7372_d4 = {
235 .genpd.name = "D4",
210 .bit_shift = 3, 236 .bit_shift = 3,
211}; 237};
212 238
213struct sh7372_pm_domain sh7372_a4r = { 239struct sh7372_pm_domain sh7372_a4r = {
240 .genpd.name = "A4R",
214 .bit_shift = 5, 241 .bit_shift = 5,
215 .gov = &sh7372_always_on_gov,
216 .suspend = sh7372_a4r_suspend, 242 .suspend = sh7372_a4r_suspend,
217 .resume = sh7372_intcs_resume, 243 .resume = sh7372_intcs_resume,
218 .stay_on = true,
219}; 244};
220 245
221struct sh7372_pm_domain sh7372_a3rv = { 246struct sh7372_pm_domain sh7372_a3rv = {
247 .genpd.name = "A3RV",
222 .bit_shift = 6, 248 .bit_shift = 6,
223}; 249};
224 250
225struct sh7372_pm_domain sh7372_a3ri = { 251struct sh7372_pm_domain sh7372_a3ri = {
252 .genpd.name = "A3RI",
226 .bit_shift = 8, 253 .bit_shift = 8,
227}; 254};
228 255
229struct sh7372_pm_domain sh7372_a3sp = { 256static int sh7372_a4s_suspend(void)
230 .bit_shift = 11, 257{
231 .gov = &sh7372_always_on_gov, 258 /*
259 * The A4S domain contains the CPU core and therefore it should
260 * only be turned off if the CPU is in use.
261 */
262 return -EBUSY;
263}
264
265struct sh7372_pm_domain sh7372_a4s = {
266 .genpd.name = "A4S",
267 .bit_shift = 10,
268 .gov = &pm_domain_always_on_gov,
232 .no_debug = true, 269 .no_debug = true,
270 .suspend = sh7372_a4s_suspend,
233}; 271};
234 272
235static void sh7372_a3sp_init(void) 273static int sh7372_a3sp_suspend(void)
236{ 274{
237 /* serial consoles make use of SCIF hardware located in A3SP, 275 /*
276 * Serial consoles make use of SCIF hardware located in A3SP,
238 * keep such power domain on if "no_console_suspend" is set. 277 * keep such power domain on if "no_console_suspend" is set.
239 */ 278 */
240 sh7372_a3sp.stay_on = !console_suspend_enabled; 279 return console_suspend_enabled ? -EBUSY : 0;
241} 280}
242 281
282struct sh7372_pm_domain sh7372_a3sp = {
283 .genpd.name = "A3SP",
284 .bit_shift = 11,
285 .gov = &pm_domain_always_on_gov,
286 .no_debug = true,
287 .suspend = sh7372_a3sp_suspend,
288};
289
243struct sh7372_pm_domain sh7372_a3sg = { 290struct sh7372_pm_domain sh7372_a3sg = {
291 .genpd.name = "A3SG",
244 .bit_shift = 13, 292 .bit_shift = 13,
245}; 293};
246 294
@@ -257,11 +305,16 @@ static int sh7372_do_idle_core_standby(unsigned long unused)
257 return 0; 305 return 0;
258} 306}
259 307
260static void sh7372_enter_core_standby(void) 308static void sh7372_set_reset_vector(unsigned long address)
261{ 309{
262 /* set reset vector, translate 4k */ 310 /* set reset vector, translate 4k */
263 __raw_writel(__pa(sh7372_resume_core_standby_a3sm), SBAR); 311 __raw_writel(address, SBAR);
264 __raw_writel(0, APARMBAREA); 312 __raw_writel(0, APARMBAREA);
313}
314
315static void sh7372_enter_core_standby(void)
316{
317 sh7372_set_reset_vector(__pa(sh7372_resume_core_standby_sysc));
265 318
266 /* enter sleep mode with SYSTBCR to 0x10 */ 319 /* enter sleep mode with SYSTBCR to 0x10 */
267 __raw_writel(0x10, SYSTBCR); 320 __raw_writel(0x10, SYSTBCR);
@@ -274,27 +327,22 @@ static void sh7372_enter_core_standby(void)
274#endif 327#endif
275 328
276#ifdef CONFIG_SUSPEND 329#ifdef CONFIG_SUSPEND
277static void sh7372_enter_a3sm_common(int pllc0_on) 330static void sh7372_enter_sysc(int pllc0_on, unsigned long sleep_mode)
278{ 331{
279 /* set reset vector, translate 4k */
280 __raw_writel(__pa(sh7372_resume_core_standby_a3sm), SBAR);
281 __raw_writel(0, APARMBAREA);
282
283 if (pllc0_on) 332 if (pllc0_on)
284 __raw_writel(0, PLLC01STPCR); 333 __raw_writel(0, PLLC01STPCR);
285 else 334 else
286 __raw_writel(1 << 28, PLLC01STPCR); 335 __raw_writel(1 << 28, PLLC01STPCR);
287 336
288 __raw_writel(0, PDNSEL); /* power-down A3SM only, not A4S */
289 __raw_readl(WUPSFAC); /* read wakeup int. factor before sleep */ 337 __raw_readl(WUPSFAC); /* read wakeup int. factor before sleep */
290 cpu_suspend(0, sh7372_do_idle_a3sm); 338 cpu_suspend(sleep_mode, sh7372_do_idle_sysc);
291 __raw_readl(WUPSFAC); /* read wakeup int. factor after wakeup */ 339 __raw_readl(WUPSFAC); /* read wakeup int. factor after wakeup */
292 340
293 /* disable reset vector translation */ 341 /* disable reset vector translation */
294 __raw_writel(0, SBAR); 342 __raw_writel(0, SBAR);
295} 343}
296 344
297static int sh7372_a3sm_valid(unsigned long *mskp, unsigned long *msk2p) 345static int sh7372_sysc_valid(unsigned long *mskp, unsigned long *msk2p)
298{ 346{
299 unsigned long mstpsr0, mstpsr1, mstpsr2, mstpsr3, mstpsr4; 347 unsigned long mstpsr0, mstpsr1, mstpsr2, mstpsr3, mstpsr4;
300 unsigned long msk, msk2; 348 unsigned long msk, msk2;
@@ -382,7 +430,7 @@ static void sh7372_icr_to_irqcr(unsigned long icr, u16 *irqcr1p, u16 *irqcr2p)
382 *irqcr2p = irqcr2; 430 *irqcr2p = irqcr2;
383} 431}
384 432
385static void sh7372_setup_a3sm(unsigned long msk, unsigned long msk2) 433static void sh7372_setup_sysc(unsigned long msk, unsigned long msk2)
386{ 434{
387 u16 irqcrx_low, irqcrx_high, irqcry_low, irqcry_high; 435 u16 irqcrx_low, irqcrx_high, irqcry_low, irqcry_high;
388 unsigned long tmp; 436 unsigned long tmp;
@@ -415,6 +463,22 @@ static void sh7372_setup_a3sm(unsigned long msk, unsigned long msk2)
415 __raw_writel((irqcrx_high << 16) | irqcrx_low, IRQCR3); 463 __raw_writel((irqcrx_high << 16) | irqcrx_low, IRQCR3);
416 __raw_writel((irqcry_high << 16) | irqcry_low, IRQCR4); 464 __raw_writel((irqcry_high << 16) | irqcry_low, IRQCR4);
417} 465}
466
467static void sh7372_enter_a3sm_common(int pllc0_on)
468{
469 sh7372_set_reset_vector(__pa(sh7372_resume_core_standby_sysc));
470 sh7372_enter_sysc(pllc0_on, 1 << 12);
471}
472
473static void sh7372_enter_a4s_common(int pllc0_on)
474{
475 sh7372_intca_suspend();
476 memcpy((void *)SMFRAM, sh7372_resume_core_standby_sysc, 0x100);
477 sh7372_set_reset_vector(SMFRAM);
478 sh7372_enter_sysc(pllc0_on, 1 << 10);
479 sh7372_intca_resume();
480}
481
418#endif 482#endif
419 483
420#ifdef CONFIG_CPU_IDLE 484#ifdef CONFIG_CPU_IDLE
@@ -448,14 +512,20 @@ static int sh7372_enter_suspend(suspend_state_t suspend_state)
448 unsigned long msk, msk2; 512 unsigned long msk, msk2;
449 513
450 /* check active clocks to determine potential wakeup sources */ 514 /* check active clocks to determine potential wakeup sources */
451 if (sh7372_a3sm_valid(&msk, &msk2)) { 515 if (sh7372_sysc_valid(&msk, &msk2)) {
452
453 /* convert INTC mask and sense to SYSC mask and sense */ 516 /* convert INTC mask and sense to SYSC mask and sense */
454 sh7372_setup_a3sm(msk, msk2); 517 sh7372_setup_sysc(msk, msk2);
455 518
456 /* enter A3SM sleep with PLLC0 off */ 519 if (!console_suspend_enabled &&
457 pr_debug("entering A3SM\n"); 520 sh7372_a4s.genpd.status == GPD_STATE_POWER_OFF) {
458 sh7372_enter_a3sm_common(0); 521 /* enter A4S sleep with PLLC0 off */
522 pr_debug("entering A4S\n");
523 sh7372_enter_a4s_common(0);
524 } else {
525 /* enter A3SM sleep with PLLC0 off */
526 pr_debug("entering A3SM\n");
527 sh7372_enter_a3sm_common(0);
528 }
459 } else { 529 } else {
460 /* default to Core Standby that supports all wakeup sources */ 530 /* default to Core Standby that supports all wakeup sources */
461 pr_debug("entering Core Standby\n"); 531 pr_debug("entering Core Standby\n");
@@ -464,9 +534,37 @@ static int sh7372_enter_suspend(suspend_state_t suspend_state)
464 return 0; 534 return 0;
465} 535}
466 536
537/**
538 * sh7372_pm_notifier_fn - SH7372 PM notifier routine.
539 * @notifier: Unused.
540 * @pm_event: Event being handled.
541 * @unused: Unused.
542 */
543static int sh7372_pm_notifier_fn(struct notifier_block *notifier,
544 unsigned long pm_event, void *unused)
545{
546 switch (pm_event) {
547 case PM_SUSPEND_PREPARE:
548 /*
549 * This is necessary, because the A4R domain has to be "on"
550 * when suspend_device_irqs() and resume_device_irqs() are
551 * executed during system suspend and resume, respectively, so
552 * that those functions don't crash while accessing the INTCS.
553 */
554 pm_genpd_poweron(&sh7372_a4r.genpd);
555 break;
556 case PM_POST_SUSPEND:
557 pm_genpd_poweroff_unused();
558 break;
559 }
560
561 return NOTIFY_DONE;
562}
563
467static void sh7372_suspend_init(void) 564static void sh7372_suspend_init(void)
468{ 565{
469 shmobile_suspend_ops.enter = sh7372_enter_suspend; 566 shmobile_suspend_ops.enter = sh7372_enter_suspend;
567 pm_notifier(sh7372_pm_notifier_fn, 0);
470} 568}
471#else 569#else
472static void sh7372_suspend_init(void) {} 570static void sh7372_suspend_init(void) {}
@@ -482,8 +580,6 @@ void __init sh7372_pm_init(void)
482 /* do not convert A3SM, A3SP, A3SG, A4R power down into A4S */ 580 /* do not convert A3SM, A3SP, A3SG, A4R power down into A4S */
483 __raw_writel(0, PDNSEL); 581 __raw_writel(0, PDNSEL);
484 582
485 sh7372_a3sp_init();
486
487 sh7372_suspend_init(); 583 sh7372_suspend_init();
488 sh7372_cpuidle_init(); 584 sh7372_cpuidle_init();
489} 585}