aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2011-12-25 17:43:11 -0500
committerRafael J. Wysocki <rjw@sisk.pl>2011-12-25 17:43:11 -0500
commit6d10463b2fa1b6b81091661c1917f26436b38c53 (patch)
tree1fb5be10a08a3178fb644c9eb5a2a31423985cfa /arch
parent0015afaa1f818d38ea9f8e81a84a6aeeca5fdaf0 (diff)
parenta8cf27bee7adc40d91956cf1b9e44d7001f93aba (diff)
Merge branch 'pm-domains' into pm-for-linus
* pm-domains: 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 ARM: S3C64XX: Implement basic power domain support PM / shmobile: Use common always on power domain governor PM / Domains: Provide an always on power domain governor PM / Domains: Fix default system suspend/resume operations PM / Domains: Make it possible to assign names to generic PM domains PM / Domains: fix compilation failure for CONFIG_PM_GENERIC_DOMAINS unset PM / Domains: Automatically update overoptimistic latency information PM / Domains: Add default power off governor function (v4) PM / Domains: Add device stop governor function (v4) PM / Domains: Rework system suspend callback routines (v2) PM / Domains: Introduce "save/restore state" device callbacks PM / Domains: Make it possible to use per-device domain callbacks
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/mach-s3c64xx/Kconfig1
-rw-r--r--arch/arm/mach-s3c64xx/mach-crag6410.c2
-rw-r--r--arch/arm/mach-s3c64xx/pm.c176
-rw-r--r--arch/arm/mach-shmobile/include/mach/common.h4
-rw-r--r--arch/arm/mach-shmobile/include/mach/sh7372.h6
-rw-r--r--arch/arm/mach-shmobile/intc-sh7372.c50
-rw-r--r--arch/arm/mach-shmobile/pm-sh7372.c196
-rw-r--r--arch/arm/mach-shmobile/setup-sh7372.c6
-rw-r--r--arch/arm/mach-shmobile/sleep-sh7372.S21
-rw-r--r--arch/arm/plat-samsung/include/plat/pm.h6
10 files changed, 400 insertions, 68 deletions
diff --git a/arch/arm/mach-s3c64xx/Kconfig b/arch/arm/mach-s3c64xx/Kconfig
index 5552e048c2be..381586c7b1b2 100644
--- a/arch/arm/mach-s3c64xx/Kconfig
+++ b/arch/arm/mach-s3c64xx/Kconfig
@@ -8,6 +8,7 @@ config PLAT_S3C64XX
8 bool 8 bool
9 depends on ARCH_S3C64XX 9 depends on ARCH_S3C64XX
10 select SAMSUNG_WAKEMASK 10 select SAMSUNG_WAKEMASK
11 select PM_GENERIC_DOMAINS
11 default y 12 default y
12 help 13 help
13 Base platform code for any Samsung S3C64XX device 14 Base platform code for any Samsung S3C64XX device
diff --git a/arch/arm/mach-s3c64xx/mach-crag6410.c b/arch/arm/mach-s3c64xx/mach-crag6410.c
index d04b65448510..707b9b22f9fd 100644
--- a/arch/arm/mach-s3c64xx/mach-crag6410.c
+++ b/arch/arm/mach-s3c64xx/mach-crag6410.c
@@ -704,7 +704,7 @@ static void __init crag6410_machine_init(void)
704 704
705 regulator_has_full_constraints(); 705 regulator_has_full_constraints();
706 706
707 s3c_pm_init(); 707 s3c64xx_pm_init();
708} 708}
709 709
710MACHINE_START(WLF_CRAGG_6410, "Wolfson Cragganmore 6410") 710MACHINE_START(WLF_CRAGG_6410, "Wolfson Cragganmore 6410")
diff --git a/arch/arm/mach-s3c64xx/pm.c b/arch/arm/mach-s3c64xx/pm.c
index b375cd5c47cb..7d3e81b9dd06 100644
--- a/arch/arm/mach-s3c64xx/pm.c
+++ b/arch/arm/mach-s3c64xx/pm.c
@@ -17,10 +17,12 @@
17#include <linux/serial_core.h> 17#include <linux/serial_core.h>
18#include <linux/io.h> 18#include <linux/io.h>
19#include <linux/gpio.h> 19#include <linux/gpio.h>
20#include <linux/pm_domain.h>
20 21
21#include <mach/map.h> 22#include <mach/map.h>
22#include <mach/irqs.h> 23#include <mach/irqs.h>
23 24
25#include <plat/devs.h>
24#include <plat/pm.h> 26#include <plat/pm.h>
25#include <plat/wakeup-mask.h> 27#include <plat/wakeup-mask.h>
26 28
@@ -31,6 +33,148 @@
31#include <mach/regs-gpio-memport.h> 33#include <mach/regs-gpio-memport.h>
32#include <mach/regs-modem.h> 34#include <mach/regs-modem.h>
33 35
36struct s3c64xx_pm_domain {
37 char *const name;
38 u32 ena;
39 u32 pwr_stat;
40 struct generic_pm_domain pd;
41};
42
43static int s3c64xx_pd_off(struct generic_pm_domain *domain)
44{
45 struct s3c64xx_pm_domain *pd;
46 u32 val;
47
48 pd = container_of(domain, struct s3c64xx_pm_domain, pd);
49
50 val = __raw_readl(S3C64XX_NORMAL_CFG);
51 val &= ~(pd->ena);
52 __raw_writel(val, S3C64XX_NORMAL_CFG);
53
54 return 0;
55}
56
57static int s3c64xx_pd_on(struct generic_pm_domain *domain)
58{
59 struct s3c64xx_pm_domain *pd;
60 u32 val;
61 long retry = 1000000L;
62
63 pd = container_of(domain, struct s3c64xx_pm_domain, pd);
64
65 val = __raw_readl(S3C64XX_NORMAL_CFG);
66 val |= pd->ena;
67 __raw_writel(val, S3C64XX_NORMAL_CFG);
68
69 /* Not all domains provide power status readback */
70 if (pd->pwr_stat) {
71 do {
72 cpu_relax();
73 if (__raw_readl(S3C64XX_BLK_PWR_STAT) & pd->pwr_stat)
74 break;
75 } while (retry--);
76
77 if (!retry) {
78 pr_err("Failed to start domain %s\n", pd->name);
79 return -EBUSY;
80 }
81 }
82
83 return 0;
84}
85
86static struct s3c64xx_pm_domain s3c64xx_pm_irom = {
87 .name = "IROM",
88 .ena = S3C64XX_NORMALCFG_IROM_ON,
89 .pd = {
90 .power_off = s3c64xx_pd_off,
91 .power_on = s3c64xx_pd_on,
92 },
93};
94
95static struct s3c64xx_pm_domain s3c64xx_pm_etm = {
96 .name = "ETM",
97 .ena = S3C64XX_NORMALCFG_DOMAIN_ETM_ON,
98 .pwr_stat = S3C64XX_BLKPWRSTAT_ETM,
99 .pd = {
100 .power_off = s3c64xx_pd_off,
101 .power_on = s3c64xx_pd_on,
102 },
103};
104
105static struct s3c64xx_pm_domain s3c64xx_pm_s = {
106 .name = "S",
107 .ena = S3C64XX_NORMALCFG_DOMAIN_S_ON,
108 .pwr_stat = S3C64XX_BLKPWRSTAT_S,
109 .pd = {
110 .power_off = s3c64xx_pd_off,
111 .power_on = s3c64xx_pd_on,
112 },
113};
114
115static struct s3c64xx_pm_domain s3c64xx_pm_f = {
116 .name = "F",
117 .ena = S3C64XX_NORMALCFG_DOMAIN_F_ON,
118 .pwr_stat = S3C64XX_BLKPWRSTAT_F,
119 .pd = {
120 .power_off = s3c64xx_pd_off,
121 .power_on = s3c64xx_pd_on,
122 },
123};
124
125static struct s3c64xx_pm_domain s3c64xx_pm_p = {
126 .name = "P",
127 .ena = S3C64XX_NORMALCFG_DOMAIN_P_ON,
128 .pwr_stat = S3C64XX_BLKPWRSTAT_P,
129 .pd = {
130 .power_off = s3c64xx_pd_off,
131 .power_on = s3c64xx_pd_on,
132 },
133};
134
135static struct s3c64xx_pm_domain s3c64xx_pm_i = {
136 .name = "I",
137 .ena = S3C64XX_NORMALCFG_DOMAIN_I_ON,
138 .pwr_stat = S3C64XX_BLKPWRSTAT_I,
139 .pd = {
140 .power_off = s3c64xx_pd_off,
141 .power_on = s3c64xx_pd_on,
142 },
143};
144
145static struct s3c64xx_pm_domain s3c64xx_pm_g = {
146 .name = "G",
147 .ena = S3C64XX_NORMALCFG_DOMAIN_G_ON,
148 .pd = {
149 .power_off = s3c64xx_pd_off,
150 .power_on = s3c64xx_pd_on,
151 },
152};
153
154static struct s3c64xx_pm_domain s3c64xx_pm_v = {
155 .name = "V",
156 .ena = S3C64XX_NORMALCFG_DOMAIN_V_ON,
157 .pwr_stat = S3C64XX_BLKPWRSTAT_V,
158 .pd = {
159 .power_off = s3c64xx_pd_off,
160 .power_on = s3c64xx_pd_on,
161 },
162};
163
164static struct s3c64xx_pm_domain *s3c64xx_always_on_pm_domains[] = {
165 &s3c64xx_pm_irom,
166};
167
168static struct s3c64xx_pm_domain *s3c64xx_pm_domains[] = {
169 &s3c64xx_pm_etm,
170 &s3c64xx_pm_g,
171 &s3c64xx_pm_v,
172 &s3c64xx_pm_i,
173 &s3c64xx_pm_p,
174 &s3c64xx_pm_s,
175 &s3c64xx_pm_f,
176};
177
34#ifdef CONFIG_S3C_PM_DEBUG_LED_SMDK 178#ifdef CONFIG_S3C_PM_DEBUG_LED_SMDK
35void s3c_pm_debug_smdkled(u32 set, u32 clear) 179void s3c_pm_debug_smdkled(u32 set, u32 clear)
36{ 180{
@@ -89,6 +233,8 @@ static struct sleep_save misc_save[] = {
89 233
90 SAVE_ITEM(S3C64XX_SDMA_SEL), 234 SAVE_ITEM(S3C64XX_SDMA_SEL),
91 SAVE_ITEM(S3C64XX_MODEM_MIFPCON), 235 SAVE_ITEM(S3C64XX_MODEM_MIFPCON),
236
237 SAVE_ITEM(S3C64XX_NORMAL_CFG),
92}; 238};
93 239
94void s3c_pm_configure_extint(void) 240void s3c_pm_configure_extint(void)
@@ -179,7 +325,26 @@ static void s3c64xx_pm_prepare(void)
179 __raw_writel(__raw_readl(S3C64XX_WAKEUP_STAT), S3C64XX_WAKEUP_STAT); 325 __raw_writel(__raw_readl(S3C64XX_WAKEUP_STAT), S3C64XX_WAKEUP_STAT);
180} 326}
181 327
182static int s3c64xx_pm_init(void) 328int __init s3c64xx_pm_init(void)
329{
330 int i;
331
332 s3c_pm_init();
333
334 for (i = 0; i < ARRAY_SIZE(s3c64xx_always_on_pm_domains); i++)
335 pm_genpd_init(&s3c64xx_always_on_pm_domains[i]->pd,
336 &pm_domain_always_on_gov, false);
337
338 for (i = 0; i < ARRAY_SIZE(s3c64xx_pm_domains); i++)
339 pm_genpd_init(&s3c64xx_pm_domains[i]->pd, NULL, false);
340
341 if (dev_get_platdata(&s3c_device_fb.dev))
342 pm_genpd_add_device(&s3c64xx_pm_f.pd, &s3c_device_fb.dev);
343
344 return 0;
345}
346
347static __init int s3c64xx_pm_initcall(void)
183{ 348{
184 pm_cpu_prep = s3c64xx_pm_prepare; 349 pm_cpu_prep = s3c64xx_pm_prepare;
185 pm_cpu_sleep = s3c64xx_cpu_suspend; 350 pm_cpu_sleep = s3c64xx_cpu_suspend;
@@ -198,5 +363,12 @@ static int s3c64xx_pm_init(void)
198 363
199 return 0; 364 return 0;
200} 365}
366arch_initcall(s3c64xx_pm_initcall);
367
368static __init int s3c64xx_pm_late_initcall(void)
369{
370 pm_genpd_poweroff_unused();
201 371
202arch_initcall(s3c64xx_pm_init); 372 return 0;
373}
374late_initcall(s3c64xx_pm_late_initcall);
diff --git a/arch/arm/mach-shmobile/include/mach/common.h b/arch/arm/mach-shmobile/include/mach/common.h
index 834bd6cd508f..4807623fb71c 100644
--- a/arch/arm/mach-shmobile/include/mach/common.h
+++ b/arch/arm/mach-shmobile/include/mach/common.h
@@ -35,8 +35,8 @@ extern void sh7372_add_standard_devices(void);
35extern void sh7372_clock_init(void); 35extern void sh7372_clock_init(void);
36extern void sh7372_pinmux_init(void); 36extern void sh7372_pinmux_init(void);
37extern void sh7372_pm_init(void); 37extern void sh7372_pm_init(void);
38extern void sh7372_resume_core_standby_a3sm(void); 38extern void sh7372_resume_core_standby_sysc(void);
39extern int sh7372_do_idle_a3sm(unsigned long unused); 39extern int sh7372_do_idle_sysc(unsigned long sleep_mode);
40extern struct clk sh7372_extal1_clk; 40extern struct clk sh7372_extal1_clk;
41extern struct clk sh7372_extal2_clk; 41extern struct clk sh7372_extal2_clk;
42 42
diff --git a/arch/arm/mach-shmobile/include/mach/sh7372.h b/arch/arm/mach-shmobile/include/mach/sh7372.h
index 84532f9629b2..8254ab86f6cd 100644
--- a/arch/arm/mach-shmobile/include/mach/sh7372.h
+++ b/arch/arm/mach-shmobile/include/mach/sh7372.h
@@ -480,11 +480,10 @@ struct platform_device;
480struct sh7372_pm_domain { 480struct sh7372_pm_domain {
481 struct generic_pm_domain genpd; 481 struct generic_pm_domain genpd;
482 struct dev_power_governor *gov; 482 struct dev_power_governor *gov;
483 void (*suspend)(void); 483 int (*suspend)(void);
484 void (*resume)(void); 484 void (*resume)(void);
485 unsigned int bit_shift; 485 unsigned int bit_shift;
486 bool no_debug; 486 bool no_debug;
487 bool stay_on;
488}; 487};
489 488
490static inline struct sh7372_pm_domain *to_sh7372_pd(struct generic_pm_domain *d) 489static inline struct sh7372_pm_domain *to_sh7372_pd(struct generic_pm_domain *d)
@@ -499,6 +498,7 @@ extern struct sh7372_pm_domain sh7372_d4;
499extern struct sh7372_pm_domain sh7372_a4r; 498extern struct sh7372_pm_domain sh7372_a4r;
500extern struct sh7372_pm_domain sh7372_a3rv; 499extern struct sh7372_pm_domain sh7372_a3rv;
501extern struct sh7372_pm_domain sh7372_a3ri; 500extern struct sh7372_pm_domain sh7372_a3ri;
501extern struct sh7372_pm_domain sh7372_a4s;
502extern struct sh7372_pm_domain sh7372_a3sp; 502extern struct sh7372_pm_domain sh7372_a3sp;
503extern struct sh7372_pm_domain sh7372_a3sg; 503extern struct sh7372_pm_domain sh7372_a3sg;
504 504
@@ -515,5 +515,7 @@ extern void sh7372_pm_add_subdomain(struct sh7372_pm_domain *sh7372_pd,
515 515
516extern void sh7372_intcs_suspend(void); 516extern void sh7372_intcs_suspend(void);
517extern void sh7372_intcs_resume(void); 517extern void sh7372_intcs_resume(void);
518extern void sh7372_intca_suspend(void);
519extern void sh7372_intca_resume(void);
518 520
519#endif /* __ASM_SH7372_H__ */ 521#endif /* __ASM_SH7372_H__ */
diff --git a/arch/arm/mach-shmobile/intc-sh7372.c b/arch/arm/mach-shmobile/intc-sh7372.c
index 2d8856df80e2..89afcaba99a1 100644
--- a/arch/arm/mach-shmobile/intc-sh7372.c
+++ b/arch/arm/mach-shmobile/intc-sh7372.c
@@ -535,6 +535,7 @@ static struct resource intcs_resources[] __initdata = {
535static struct intc_desc intcs_desc __initdata = { 535static struct intc_desc intcs_desc __initdata = {
536 .name = "sh7372-intcs", 536 .name = "sh7372-intcs",
537 .force_enable = ENABLED_INTCS, 537 .force_enable = ENABLED_INTCS,
538 .skip_syscore_suspend = true,
538 .resource = intcs_resources, 539 .resource = intcs_resources,
539 .num_resources = ARRAY_SIZE(intcs_resources), 540 .num_resources = ARRAY_SIZE(intcs_resources),
540 .hw = INTC_HW_DESC(intcs_vectors, intcs_groups, intcs_mask_registers, 541 .hw = INTC_HW_DESC(intcs_vectors, intcs_groups, intcs_mask_registers,
@@ -611,3 +612,52 @@ void sh7372_intcs_resume(void)
611 for (k = 0x80; k <= 0x9c; k += 4) 612 for (k = 0x80; k <= 0x9c; k += 4)
612 __raw_writeb(ffd5[k], intcs_ffd5 + k); 613 __raw_writeb(ffd5[k], intcs_ffd5 + k);
613} 614}
615
616static unsigned short e694[0x200];
617static unsigned short e695[0x200];
618
619void sh7372_intca_suspend(void)
620{
621 int k;
622
623 for (k = 0x00; k <= 0x38; k += 4)
624 e694[k] = __raw_readw(0xe6940000 + k);
625
626 for (k = 0x80; k <= 0xb4; k += 4)
627 e694[k] = __raw_readb(0xe6940000 + k);
628
629 for (k = 0x180; k <= 0x1b4; k += 4)
630 e694[k] = __raw_readb(0xe6940000 + k);
631
632 for (k = 0x00; k <= 0x50; k += 4)
633 e695[k] = __raw_readw(0xe6950000 + k);
634
635 for (k = 0x80; k <= 0xa8; k += 4)
636 e695[k] = __raw_readb(0xe6950000 + k);
637
638 for (k = 0x180; k <= 0x1a8; k += 4)
639 e695[k] = __raw_readb(0xe6950000 + k);
640}
641
642void sh7372_intca_resume(void)
643{
644 int k;
645
646 for (k = 0x00; k <= 0x38; k += 4)
647 __raw_writew(e694[k], 0xe6940000 + k);
648
649 for (k = 0x80; k <= 0xb4; k += 4)
650 __raw_writeb(e694[k], 0xe6940000 + k);
651
652 for (k = 0x180; k <= 0x1b4; k += 4)
653 __raw_writeb(e694[k], 0xe6940000 + k);
654
655 for (k = 0x00; k <= 0x50; k += 4)
656 __raw_writew(e695[k], 0xe6950000 + k);
657
658 for (k = 0x80; k <= 0xa8; k += 4)
659 __raw_writeb(e695[k], 0xe6950000 + k);
660
661 for (k = 0x180; k <= 0x1a8; k += 4)
662 __raw_writeb(e695[k], 0xe6950000 + k);
663}
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}
diff --git a/arch/arm/mach-shmobile/setup-sh7372.c b/arch/arm/mach-shmobile/setup-sh7372.c
index 2380389e6ac5..c197f9d29d04 100644
--- a/arch/arm/mach-shmobile/setup-sh7372.c
+++ b/arch/arm/mach-shmobile/setup-sh7372.c
@@ -994,12 +994,16 @@ void __init sh7372_add_standard_devices(void)
994 sh7372_init_pm_domain(&sh7372_a4r); 994 sh7372_init_pm_domain(&sh7372_a4r);
995 sh7372_init_pm_domain(&sh7372_a3rv); 995 sh7372_init_pm_domain(&sh7372_a3rv);
996 sh7372_init_pm_domain(&sh7372_a3ri); 996 sh7372_init_pm_domain(&sh7372_a3ri);
997 sh7372_init_pm_domain(&sh7372_a3sg); 997 sh7372_init_pm_domain(&sh7372_a4s);
998 sh7372_init_pm_domain(&sh7372_a3sp); 998 sh7372_init_pm_domain(&sh7372_a3sp);
999 sh7372_init_pm_domain(&sh7372_a3sg);
999 1000
1000 sh7372_pm_add_subdomain(&sh7372_a4lc, &sh7372_a3rv); 1001 sh7372_pm_add_subdomain(&sh7372_a4lc, &sh7372_a3rv);
1001 sh7372_pm_add_subdomain(&sh7372_a4r, &sh7372_a4lc); 1002 sh7372_pm_add_subdomain(&sh7372_a4r, &sh7372_a4lc);
1002 1003
1004 sh7372_pm_add_subdomain(&sh7372_a4s, &sh7372_a3sg);
1005 sh7372_pm_add_subdomain(&sh7372_a4s, &sh7372_a3sp);
1006
1003 platform_add_devices(sh7372_early_devices, 1007 platform_add_devices(sh7372_early_devices,
1004 ARRAY_SIZE(sh7372_early_devices)); 1008 ARRAY_SIZE(sh7372_early_devices));
1005 1009
diff --git a/arch/arm/mach-shmobile/sleep-sh7372.S b/arch/arm/mach-shmobile/sleep-sh7372.S
index f3ab3c5810ea..1d564674451d 100644
--- a/arch/arm/mach-shmobile/sleep-sh7372.S
+++ b/arch/arm/mach-shmobile/sleep-sh7372.S
@@ -37,13 +37,18 @@
37#if defined(CONFIG_SUSPEND) || defined(CONFIG_CPU_IDLE) 37#if defined(CONFIG_SUSPEND) || defined(CONFIG_CPU_IDLE)
38 .align 12 38 .align 12
39 .text 39 .text
40 .global sh7372_resume_core_standby_a3sm 40 .global sh7372_resume_core_standby_sysc
41sh7372_resume_core_standby_a3sm: 41sh7372_resume_core_standby_sysc:
42 ldr pc, 1f 42 ldr pc, 1f
431: .long cpu_resume - PAGE_OFFSET + PLAT_PHYS_OFFSET 431: .long cpu_resume - PAGE_OFFSET + PLAT_PHYS_OFFSET
44 44
45 .global sh7372_do_idle_a3sm 45#define SPDCR 0xe6180008
46sh7372_do_idle_a3sm: 46
47 /* A3SM & A4S power down */
48 .global sh7372_do_idle_sysc
49sh7372_do_idle_sysc:
50 mov r8, r0 /* sleep mode passed in r0 */
51
47 /* 52 /*
48 * Clear the SCTLR.C bit to prevent further data cache 53 * Clear the SCTLR.C bit to prevent further data cache
49 * allocation. Clearing SCTLR.C would make all the data accesses 54 * allocation. Clearing SCTLR.C would make all the data accesses
@@ -80,13 +85,9 @@ sh7372_do_idle_a3sm:
80 dsb 85 dsb
81 dmb 86 dmb
82 87
83#define SPDCR 0xe6180008 88 /* SYSC power down */
84#define A3SM (1 << 12)
85
86 /* A3SM power down */
87 ldr r0, =SPDCR 89 ldr r0, =SPDCR
88 ldr r1, =A3SM 90 str r8, [r0]
89 str r1, [r0]
901: 911:
91 b 1b 92 b 1b
92 93
diff --git a/arch/arm/plat-samsung/include/plat/pm.h b/arch/arm/plat-samsung/include/plat/pm.h
index dcf68709f9cf..a6bdee204f2a 100644
--- a/arch/arm/plat-samsung/include/plat/pm.h
+++ b/arch/arm/plat-samsung/include/plat/pm.h
@@ -22,6 +22,7 @@ struct sys_device;
22#ifdef CONFIG_PM 22#ifdef CONFIG_PM
23 23
24extern __init int s3c_pm_init(void); 24extern __init int s3c_pm_init(void);
25extern __init int s3c64xx_pm_init(void);
25 26
26#else 27#else
27 28
@@ -29,6 +30,11 @@ static inline int s3c_pm_init(void)
29{ 30{
30 return 0; 31 return 0;
31} 32}
33
34static inline int s3c64xx_pm_init(void)
35{
36 return 0;
37}
32#endif 38#endif
33 39
34/* configuration for the IRQ mask over sleep */ 40/* configuration for the IRQ mask over sleep */