diff options
Diffstat (limited to 'arch/arm/mach-shmobile')
-rw-r--r-- | arch/arm/mach-shmobile/Makefile | 1 | ||||
-rw-r--r-- | arch/arm/mach-shmobile/include/mach/common.h | 1 | ||||
-rw-r--r-- | arch/arm/mach-shmobile/include/mach/r8a7779.h | 35 | ||||
-rw-r--r-- | arch/arm/mach-shmobile/pm-r8a7779.c | 235 | ||||
-rw-r--r-- | arch/arm/mach-shmobile/setup-r8a7779.c | 8 |
5 files changed, 280 insertions, 0 deletions
diff --git a/arch/arm/mach-shmobile/Makefile b/arch/arm/mach-shmobile/Makefile index 6f6ef3ad4db1..b0d0d4b1ccbf 100644 --- a/arch/arm/mach-shmobile/Makefile +++ b/arch/arm/mach-shmobile/Makefile | |||
@@ -38,6 +38,7 @@ obj-$(CONFIG_ARCH_R8A7740) += entry-intc.o | |||
38 | obj-$(CONFIG_SUSPEND) += suspend.o | 38 | obj-$(CONFIG_SUSPEND) += suspend.o |
39 | obj-$(CONFIG_CPU_IDLE) += cpuidle.o | 39 | obj-$(CONFIG_CPU_IDLE) += cpuidle.o |
40 | obj-$(CONFIG_ARCH_SH7372) += pm-sh7372.o sleep-sh7372.o | 40 | obj-$(CONFIG_ARCH_SH7372) += pm-sh7372.o sleep-sh7372.o |
41 | obj-$(CONFIG_ARCH_R8A7779) += pm-r8a7779.o | ||
41 | 42 | ||
42 | # Board objects | 43 | # Board objects |
43 | obj-$(CONFIG_MACH_G3EVM) += board-g3evm.o | 44 | obj-$(CONFIG_MACH_G3EVM) += board-g3evm.o |
diff --git a/arch/arm/mach-shmobile/include/mach/common.h b/arch/arm/mach-shmobile/include/mach/common.h index 304ac3115338..44ce124bfdec 100644 --- a/arch/arm/mach-shmobile/include/mach/common.h +++ b/arch/arm/mach-shmobile/include/mach/common.h | |||
@@ -66,5 +66,6 @@ extern void r8a7779_add_early_devices(void); | |||
66 | extern void r8a7779_add_standard_devices(void); | 66 | extern void r8a7779_add_standard_devices(void); |
67 | extern void r8a7779_clock_init(void); | 67 | extern void r8a7779_clock_init(void); |
68 | extern void r8a7779_pinmux_init(void); | 68 | extern void r8a7779_pinmux_init(void); |
69 | extern void r8a7779_pm_init(void); | ||
69 | 70 | ||
70 | #endif /* __ARCH_MACH_COMMON_H */ | 71 | #endif /* __ARCH_MACH_COMMON_H */ |
diff --git a/arch/arm/mach-shmobile/include/mach/r8a7779.h b/arch/arm/mach-shmobile/include/mach/r8a7779.h index 60e101aaea93..e6a6166fdf22 100644 --- a/arch/arm/mach-shmobile/include/mach/r8a7779.h +++ b/arch/arm/mach-shmobile/include/mach/r8a7779.h | |||
@@ -1,6 +1,9 @@ | |||
1 | #ifndef __ASM_R8A7779_H__ | 1 | #ifndef __ASM_R8A7779_H__ |
2 | #define __ASM_R8A7779_H__ | 2 | #define __ASM_R8A7779_H__ |
3 | 3 | ||
4 | #include <linux/sh_clk.h> | ||
5 | #include <linux/pm_domain.h> | ||
6 | |||
4 | /* Pin Function Controller: | 7 | /* Pin Function Controller: |
5 | * GPIO_FN_xx - GPIO used to select pin function | 8 | * GPIO_FN_xx - GPIO used to select pin function |
6 | * GPIO_GP_x_x - GPIO mapped to real I/O pin on CPU | 9 | * GPIO_GP_x_x - GPIO mapped to real I/O pin on CPU |
@@ -322,4 +325,36 @@ enum { | |||
322 | GPIO_FN_GPS_MAG, GPIO_FN_FCE, GPIO_FN_SCK4_B, | 325 | GPIO_FN_GPS_MAG, GPIO_FN_FCE, GPIO_FN_SCK4_B, |
323 | }; | 326 | }; |
324 | 327 | ||
328 | struct platform_device; | ||
329 | |||
330 | struct r8a7779_pm_ch { | ||
331 | unsigned long chan_offs; | ||
332 | unsigned int chan_bit; | ||
333 | unsigned int isr_bit; | ||
334 | }; | ||
335 | |||
336 | struct r8a7779_pm_domain { | ||
337 | struct generic_pm_domain genpd; | ||
338 | struct r8a7779_pm_ch ch; | ||
339 | }; | ||
340 | |||
341 | static inline struct r8a7779_pm_ch *to_r8a7779_ch(struct generic_pm_domain *d) | ||
342 | { | ||
343 | return &container_of(d, struct r8a7779_pm_domain, genpd)->ch; | ||
344 | } | ||
345 | |||
346 | #ifdef CONFIG_PM | ||
347 | extern struct r8a7779_pm_domain r8a7779_sh4a; | ||
348 | extern struct r8a7779_pm_domain r8a7779_sgx; | ||
349 | extern struct r8a7779_pm_domain r8a7779_vdp1; | ||
350 | extern struct r8a7779_pm_domain r8a7779_impx3; | ||
351 | |||
352 | extern void r8a7779_init_pm_domain(struct r8a7779_pm_domain *r8a7779_pd); | ||
353 | extern void r8a7779_add_device_to_domain(struct r8a7779_pm_domain *r8a7779_pd, | ||
354 | struct platform_device *pdev); | ||
355 | #else | ||
356 | #define r8a7779_init_pm_domain(pd) do { } while (0) | ||
357 | #define r8a7779_add_device_to_domain(pd, pdev) do { } while (0) | ||
358 | #endif /* CONFIG_PM */ | ||
359 | |||
325 | #endif /* __ASM_R8A7779_H__ */ | 360 | #endif /* __ASM_R8A7779_H__ */ |
diff --git a/arch/arm/mach-shmobile/pm-r8a7779.c b/arch/arm/mach-shmobile/pm-r8a7779.c new file mode 100644 index 000000000000..d9c56fe067a5 --- /dev/null +++ b/arch/arm/mach-shmobile/pm-r8a7779.c | |||
@@ -0,0 +1,235 @@ | |||
1 | /* | ||
2 | * r8a7779 Power management support | ||
3 | * | ||
4 | * Copyright (C) 2011 Renesas Solutions Corp. | ||
5 | * Copyright (C) 2011 Magnus Damm | ||
6 | * | ||
7 | * This file is subject to the terms and conditions of the GNU General Public | ||
8 | * License. See the file "COPYING" in the main directory of this archive | ||
9 | * for more details. | ||
10 | */ | ||
11 | |||
12 | #include <linux/pm.h> | ||
13 | #include <linux/suspend.h> | ||
14 | #include <linux/err.h> | ||
15 | #include <linux/pm_clock.h> | ||
16 | #include <linux/platform_device.h> | ||
17 | #include <linux/delay.h> | ||
18 | #include <linux/irq.h> | ||
19 | #include <linux/interrupt.h> | ||
20 | #include <linux/console.h> | ||
21 | #include <asm/system.h> | ||
22 | #include <asm/io.h> | ||
23 | #include <mach/common.h> | ||
24 | #include <mach/r8a7779.h> | ||
25 | |||
26 | static void __iomem *r8a7779_sysc_base; | ||
27 | |||
28 | /* SYSC */ | ||
29 | #define SYSCSR 0x00 | ||
30 | #define SYSCISR 0x04 | ||
31 | #define SYSCISCR 0x08 | ||
32 | #define SYSCIER 0x0c | ||
33 | #define SYSCIMR 0x10 | ||
34 | #define PWRSR0 0x40 | ||
35 | #define PWRSR1 0x80 | ||
36 | #define PWRSR2 0xc0 | ||
37 | #define PWRSR3 0x100 | ||
38 | #define PWRSR4 0x140 | ||
39 | |||
40 | #define PWRSR_OFFS 0x00 | ||
41 | #define PWROFFCR_OFFS 0x04 | ||
42 | #define PWRONCR_OFFS 0x0c | ||
43 | #define PWRER_OFFS 0x14 | ||
44 | |||
45 | #define SYSCSR_RETRIES 100 | ||
46 | #define SYSCSR_DELAY_US 1 | ||
47 | |||
48 | #define SYSCISR_RETRIES 1000 | ||
49 | #define SYSCISR_DELAY_US 1 | ||
50 | |||
51 | #ifdef CONFIG_PM | ||
52 | |||
53 | static int r8a7779_sysc_pwr_on_off(struct r8a7779_pm_ch *r8a7779_ch, | ||
54 | int sr_bit, int reg_offs) | ||
55 | { | ||
56 | int k; | ||
57 | |||
58 | for (k = 0; k < SYSCSR_RETRIES; k++) { | ||
59 | if (ioread32(r8a7779_sysc_base + SYSCSR) & (1 << sr_bit)) | ||
60 | break; | ||
61 | udelay(SYSCSR_DELAY_US); | ||
62 | } | ||
63 | |||
64 | if (k == SYSCSR_RETRIES) | ||
65 | return -EAGAIN; | ||
66 | |||
67 | iowrite32(1 << r8a7779_ch->chan_bit, | ||
68 | r8a7779_sysc_base + r8a7779_ch->chan_offs + reg_offs); | ||
69 | |||
70 | return 0; | ||
71 | } | ||
72 | |||
73 | static int r8a7779_sysc_pwr_off(struct r8a7779_pm_ch *r8a7779_ch) | ||
74 | { | ||
75 | return r8a7779_sysc_pwr_on_off(r8a7779_ch, 0, PWROFFCR_OFFS); | ||
76 | } | ||
77 | |||
78 | static int r8a7779_sysc_pwr_on(struct r8a7779_pm_ch *r8a7779_ch) | ||
79 | { | ||
80 | return r8a7779_sysc_pwr_on_off(r8a7779_ch, 1, PWRONCR_OFFS); | ||
81 | } | ||
82 | |||
83 | static int r8a7779_sysc_update(struct r8a7779_pm_ch *r8a7779_ch, | ||
84 | int (*on_off_fn)(struct r8a7779_pm_ch *)) | ||
85 | { | ||
86 | unsigned int isr_mask = 1 << r8a7779_ch->isr_bit; | ||
87 | unsigned int chan_mask = 1 << r8a7779_ch->chan_bit; | ||
88 | unsigned int status; | ||
89 | int ret = 0; | ||
90 | int k; | ||
91 | |||
92 | iowrite32(isr_mask, r8a7779_sysc_base + SYSCISCR); | ||
93 | |||
94 | do { | ||
95 | ret = on_off_fn(r8a7779_ch); | ||
96 | if (ret) | ||
97 | goto out; | ||
98 | |||
99 | status = ioread32(r8a7779_sysc_base + | ||
100 | r8a7779_ch->chan_offs + PWRER_OFFS); | ||
101 | } while (status & chan_mask); | ||
102 | |||
103 | for (k = 0; k < SYSCISR_RETRIES; k++) { | ||
104 | if (ioread32(r8a7779_sysc_base + SYSCISR) & isr_mask) | ||
105 | break; | ||
106 | udelay(SYSCISR_DELAY_US); | ||
107 | } | ||
108 | |||
109 | if (k == SYSCISR_RETRIES) | ||
110 | ret = -EIO; | ||
111 | |||
112 | iowrite32(isr_mask, r8a7779_sysc_base + SYSCISCR); | ||
113 | |||
114 | out: | ||
115 | pr_debug("r8a7779 power domain %d: %02x %02x %02x %02x %02x -> %d\n", | ||
116 | r8a7779_ch->isr_bit, ioread32(r8a7779_sysc_base + PWRSR0), | ||
117 | ioread32(r8a7779_sysc_base + PWRSR1), | ||
118 | ioread32(r8a7779_sysc_base + PWRSR2), | ||
119 | ioread32(r8a7779_sysc_base + PWRSR3), | ||
120 | ioread32(r8a7779_sysc_base + PWRSR4), ret); | ||
121 | return ret; | ||
122 | } | ||
123 | |||
124 | static int r8a7779_sysc_power_down(struct r8a7779_pm_ch *r8a7779_ch) | ||
125 | { | ||
126 | return r8a7779_sysc_update(r8a7779_ch, r8a7779_sysc_pwr_off); | ||
127 | } | ||
128 | |||
129 | static int r8a7779_sysc_power_up(struct r8a7779_pm_ch *r8a7779_ch) | ||
130 | { | ||
131 | return r8a7779_sysc_update(r8a7779_ch, r8a7779_sysc_pwr_on); | ||
132 | } | ||
133 | |||
134 | static void __init r8a7779_sysc_init(void) | ||
135 | { | ||
136 | r8a7779_sysc_base = ioremap_nocache(0xffd85000, PAGE_SIZE); | ||
137 | if (!r8a7779_sysc_base) | ||
138 | panic("unable to ioremap r8a7779 SYSC hardware block\n"); | ||
139 | |||
140 | /* enable all interrupt sources, but do not use interrupt handler */ | ||
141 | iowrite32(0x0131000e, r8a7779_sysc_base + SYSCIER); | ||
142 | iowrite32(0, r8a7779_sysc_base + SYSCIMR); | ||
143 | } | ||
144 | |||
145 | static int pd_power_down(struct generic_pm_domain *genpd) | ||
146 | { | ||
147 | return r8a7779_sysc_power_down(to_r8a7779_ch(genpd)); | ||
148 | } | ||
149 | |||
150 | static int pd_power_up(struct generic_pm_domain *genpd) | ||
151 | { | ||
152 | return r8a7779_sysc_power_up(to_r8a7779_ch(genpd)); | ||
153 | } | ||
154 | |||
155 | static bool pd_is_off(struct generic_pm_domain *genpd) | ||
156 | { | ||
157 | struct r8a7779_pm_ch *r8a7779_ch = to_r8a7779_ch(genpd); | ||
158 | unsigned int st; | ||
159 | |||
160 | st = ioread32(r8a7779_sysc_base + r8a7779_ch->chan_offs + PWRSR_OFFS); | ||
161 | if (st & (1 << r8a7779_ch->chan_bit)) | ||
162 | return true; | ||
163 | |||
164 | return false; | ||
165 | } | ||
166 | |||
167 | static bool pd_active_wakeup(struct device *dev) | ||
168 | { | ||
169 | return true; | ||
170 | } | ||
171 | |||
172 | void r8a7779_init_pm_domain(struct r8a7779_pm_domain *r8a7779_pd) | ||
173 | { | ||
174 | struct generic_pm_domain *genpd = &r8a7779_pd->genpd; | ||
175 | |||
176 | pm_genpd_init(genpd, NULL, false); | ||
177 | genpd->dev_ops.stop = pm_clk_suspend; | ||
178 | genpd->dev_ops.start = pm_clk_resume; | ||
179 | genpd->dev_ops.active_wakeup = pd_active_wakeup; | ||
180 | genpd->dev_irq_safe = true; | ||
181 | genpd->power_off = pd_power_down; | ||
182 | genpd->power_on = pd_power_up; | ||
183 | |||
184 | if (pd_is_off(&r8a7779_pd->genpd)) | ||
185 | pd_power_up(&r8a7779_pd->genpd); | ||
186 | } | ||
187 | |||
188 | void r8a7779_add_device_to_domain(struct r8a7779_pm_domain *r8a7779_pd, | ||
189 | struct platform_device *pdev) | ||
190 | { | ||
191 | struct device *dev = &pdev->dev; | ||
192 | |||
193 | pm_genpd_add_device(&r8a7779_pd->genpd, dev); | ||
194 | if (pm_clk_no_clocks(dev)) | ||
195 | pm_clk_add(dev, NULL); | ||
196 | } | ||
197 | |||
198 | struct r8a7779_pm_domain r8a7779_sh4a = { | ||
199 | .ch = { | ||
200 | .chan_offs = 0x80, /* PWRSR1 .. PWRER1 */ | ||
201 | .isr_bit = 16, /* SH4A */ | ||
202 | } | ||
203 | }; | ||
204 | |||
205 | struct r8a7779_pm_domain r8a7779_sgx = { | ||
206 | .ch = { | ||
207 | .chan_offs = 0xc0, /* PWRSR2 .. PWRER2 */ | ||
208 | .isr_bit = 20, /* SGX */ | ||
209 | } | ||
210 | }; | ||
211 | |||
212 | struct r8a7779_pm_domain r8a7779_vdp1 = { | ||
213 | .ch = { | ||
214 | .chan_offs = 0x100, /* PWRSR3 .. PWRER3 */ | ||
215 | .isr_bit = 21, /* VDP */ | ||
216 | } | ||
217 | }; | ||
218 | |||
219 | struct r8a7779_pm_domain r8a7779_impx3 = { | ||
220 | .ch = { | ||
221 | .chan_offs = 0x140, /* PWRSR4 .. PWRER4 */ | ||
222 | .isr_bit = 24, /* IMP */ | ||
223 | } | ||
224 | }; | ||
225 | |||
226 | #else /* CONFIG_PM */ | ||
227 | |||
228 | static inline void r8a7779_sysc_init(void) {} | ||
229 | |||
230 | #endif /* CONFIG_PM */ | ||
231 | |||
232 | void __init r8a7779_pm_init(void) | ||
233 | { | ||
234 | r8a7779_sysc_init(); | ||
235 | } | ||
diff --git a/arch/arm/mach-shmobile/setup-r8a7779.c b/arch/arm/mach-shmobile/setup-r8a7779.c index b48a4b049c32..4725663bd032 100644 --- a/arch/arm/mach-shmobile/setup-r8a7779.c +++ b/arch/arm/mach-shmobile/setup-r8a7779.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include <linux/sh_timer.h> | 30 | #include <linux/sh_timer.h> |
31 | #include <mach/hardware.h> | 31 | #include <mach/hardware.h> |
32 | #include <mach/r8a7779.h> | 32 | #include <mach/r8a7779.h> |
33 | #include <mach/common.h> | ||
33 | #include <asm/mach-types.h> | 34 | #include <asm/mach-types.h> |
34 | #include <asm/mach/arch.h> | 35 | #include <asm/mach/arch.h> |
35 | 36 | ||
@@ -218,6 +219,13 @@ static struct platform_device *r8a7779_late_devices[] __initdata = { | |||
218 | 219 | ||
219 | void __init r8a7779_add_standard_devices(void) | 220 | void __init r8a7779_add_standard_devices(void) |
220 | { | 221 | { |
222 | r8a7779_pm_init(); | ||
223 | |||
224 | r8a7779_init_pm_domain(&r8a7779_sh4a); | ||
225 | r8a7779_init_pm_domain(&r8a7779_sgx); | ||
226 | r8a7779_init_pm_domain(&r8a7779_vdp1); | ||
227 | r8a7779_init_pm_domain(&r8a7779_impx3); | ||
228 | |||
221 | platform_add_devices(r8a7779_early_devices, | 229 | platform_add_devices(r8a7779_early_devices, |
222 | ARRAY_SIZE(r8a7779_early_devices)); | 230 | ARRAY_SIZE(r8a7779_early_devices)); |
223 | platform_add_devices(r8a7779_late_devices, | 231 | platform_add_devices(r8a7779_late_devices, |