aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorMark Brown <broonie@opensource.wolfsonmicro.com>2011-12-08 17:27:48 -0500
committerRafael J. Wysocki <rjw@sisk.pl>2011-12-09 17:22:59 -0500
commitc656c30668b9408c46d6bfbd1eea472f39a3155d (patch)
tree607b3a98acb6b0454c4cea442a20bf7052c2aa09 /arch
parenta87dc8fdc250f6416b522a3eb302c8cf95c2317c (diff)
ARM: S3C64XX: Implement basic power domain support
The S3C64xx SoCs contain a set of gateable power domains which can be enabled and disabled at runtime in order to save power. Use the generic power domain code to implement support for these in software, enabling runtime control of most domains: - ETM (not supported in mainline). - Domain G: 3D acceleration (no mainline support). - Domain V: MFC (no mainline support). - Domain I: JPEG and camera interface (no mainline support). - Domain P: 2D acceleration, TV encoder and scaler (no mainline support) - Domain S: Security (no mainline support). - Domain F: LCD (driver already uses runtime PM), post processing and rotation (no mainline support). The IROM domain is marked as always enabled as we should arrange for it to be enabled when we suspend which will need a bit more work. Due to all the conditional device registration that the platform does wrap s3c_pm_init() with s3c64xx_pm_init() which actually puts the device into the power domain after the machines have registered, looking for platform data to tell if the device was registered. Since currently only Cragganmore actually sets up PM that is the only machine updated. Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com> Acked-by: Kukjin Kim <kgene.kim@samsung.com> Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
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/plat-samsung/include/plat/pm.h6
4 files changed, 182 insertions, 3 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/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 */