]> git.karo-electronics.de Git - karo-tx-linux.git/blob - arch/arm/mach-shmobile/pm-sh7372.c
Merge branch 'next/soc' into HEAD
[karo-tx-linux.git] / arch / arm / mach-shmobile / pm-sh7372.c
1 /*
2  * sh7372 Power management support
3  *
4  *  Copyright (C) 2011 Magnus Damm
5  *
6  * This file is subject to the terms and conditions of the GNU General Public
7  * License.  See the file "COPYING" in the main directory of this archive
8  * for more details.
9  */
10
11 #include <linux/pm.h>
12 #include <linux/suspend.h>
13 #include <linux/cpuidle.h>
14 #include <linux/module.h>
15 #include <linux/list.h>
16 #include <linux/err.h>
17 #include <linux/slab.h>
18 #include <linux/pm_clock.h>
19 #include <linux/platform_device.h>
20 #include <linux/delay.h>
21 #include <linux/irq.h>
22 #include <linux/bitrev.h>
23 #include <linux/console.h>
24 #include <asm/io.h>
25 #include <asm/tlbflush.h>
26 #include <asm/suspend.h>
27 #include <mach/common.h>
28 #include <mach/sh7372.h>
29 #include <mach/pm-rmobile.h>
30
31 /* DBG */
32 #define DBGREG1 IOMEM(0xe6100020)
33 #define DBGREG9 IOMEM(0xe6100040)
34
35 /* CPGA */
36 #define SYSTBCR IOMEM(0xe6150024)
37 #define MSTPSR0 IOMEM(0xe6150030)
38 #define MSTPSR1 IOMEM(0xe6150038)
39 #define MSTPSR2 IOMEM(0xe6150040)
40 #define MSTPSR3 IOMEM(0xe6150048)
41 #define MSTPSR4 IOMEM(0xe615004c)
42 #define PLLC01STPCR IOMEM(0xe61500c8)
43
44 /* SYSC */
45 #define SBAR IOMEM(0xe6180020)
46 #define WUPRMSK IOMEM(0xe6180028)
47 #define WUPSMSK IOMEM(0xe618002c)
48 #define WUPSMSK2 IOMEM(0xe6180048)
49 #define WUPSFAC IOMEM(0xe6180098)
50 #define IRQCR IOMEM(0xe618022c)
51 #define IRQCR2 IOMEM(0xe6180238)
52 #define IRQCR3 IOMEM(0xe6180244)
53 #define IRQCR4 IOMEM(0xe6180248)
54 #define PDNSEL IOMEM(0xe6180254)
55
56 /* INTC */
57 #define ICR1A IOMEM(0xe6900000)
58 #define ICR2A IOMEM(0xe6900004)
59 #define ICR3A IOMEM(0xe6900008)
60 #define ICR4A IOMEM(0xe690000c)
61 #define INTMSK00A IOMEM(0xe6900040)
62 #define INTMSK10A IOMEM(0xe6900044)
63 #define INTMSK20A IOMEM(0xe6900048)
64 #define INTMSK30A IOMEM(0xe690004c)
65
66 /* MFIS */
67 /* FIXME: pointing where? */
68 #define SMFRAM 0xe6a70000
69
70 /* AP-System Core */
71 #define APARMBAREA IOMEM(0xe6f10020)
72
73 #ifdef CONFIG_PM
74
75 struct rmobile_pm_domain sh7372_pd_a4lc = {
76         .genpd.name = "A4LC",
77         .bit_shift = 1,
78 };
79
80 struct rmobile_pm_domain sh7372_pd_a4mp = {
81         .genpd.name = "A4MP",
82         .bit_shift = 2,
83 };
84
85 struct rmobile_pm_domain sh7372_pd_d4 = {
86         .genpd.name = "D4",
87         .bit_shift = 3,
88 };
89
90 static int sh7372_a4r_pd_suspend(void)
91 {
92         sh7372_intcs_suspend();
93         __raw_writel(0x300fffff, WUPRMSK); /* avoid wakeup */
94         return 0;
95 }
96
97 struct rmobile_pm_domain sh7372_pd_a4r = {
98         .genpd.name = "A4R",
99         .bit_shift = 5,
100         .suspend = sh7372_a4r_pd_suspend,
101         .resume = sh7372_intcs_resume,
102 };
103
104 struct rmobile_pm_domain sh7372_pd_a3rv = {
105         .genpd.name = "A3RV",
106         .bit_shift = 6,
107 };
108
109 struct rmobile_pm_domain sh7372_pd_a3ri = {
110         .genpd.name = "A3RI",
111         .bit_shift = 8,
112 };
113
114 static int sh7372_pd_a4s_suspend(void)
115 {
116         /*
117          * The A4S domain contains the CPU core and therefore it should
118          * only be turned off if the CPU is in use.
119          */
120         return -EBUSY;
121 }
122
123 struct rmobile_pm_domain sh7372_pd_a4s = {
124         .genpd.name = "A4S",
125         .bit_shift = 10,
126         .gov = &pm_domain_always_on_gov,
127         .no_debug = true,
128         .suspend = sh7372_pd_a4s_suspend,
129 };
130
131 static int sh7372_a3sp_pd_suspend(void)
132 {
133         /*
134          * Serial consoles make use of SCIF hardware located in A3SP,
135          * keep such power domain on if "no_console_suspend" is set.
136          */
137         return console_suspend_enabled ? 0 : -EBUSY;
138 }
139
140 struct rmobile_pm_domain sh7372_pd_a3sp = {
141         .genpd.name = "A3SP",
142         .bit_shift = 11,
143         .gov = &pm_domain_always_on_gov,
144         .no_debug = true,
145         .suspend = sh7372_a3sp_pd_suspend,
146 };
147
148 struct rmobile_pm_domain sh7372_pd_a3sg = {
149         .genpd.name = "A3SG",
150         .bit_shift = 13,
151 };
152
153 #endif /* CONFIG_PM */
154
155 #if defined(CONFIG_SUSPEND) || defined(CONFIG_CPU_IDLE)
156 static void sh7372_set_reset_vector(unsigned long address)
157 {
158         /* set reset vector, translate 4k */
159         __raw_writel(address, SBAR);
160         __raw_writel(0, APARMBAREA);
161 }
162
163 static void sh7372_enter_sysc(int pllc0_on, unsigned long sleep_mode)
164 {
165         if (pllc0_on)
166                 __raw_writel(0, PLLC01STPCR);
167         else
168                 __raw_writel(1 << 28, PLLC01STPCR);
169
170         __raw_readl(WUPSFAC); /* read wakeup int. factor before sleep */
171         cpu_suspend(sleep_mode, sh7372_do_idle_sysc);
172         __raw_readl(WUPSFAC); /* read wakeup int. factor after wakeup */
173
174          /* disable reset vector translation */
175         __raw_writel(0, SBAR);
176 }
177
178 static int sh7372_sysc_valid(unsigned long *mskp, unsigned long *msk2p)
179 {
180         unsigned long mstpsr0, mstpsr1, mstpsr2, mstpsr3, mstpsr4;
181         unsigned long msk, msk2;
182
183         /* check active clocks to determine potential wakeup sources */
184
185         mstpsr0 = __raw_readl(MSTPSR0);
186         if ((mstpsr0 & 0x00000003) != 0x00000003) {
187                 pr_debug("sh7372 mstpsr0 0x%08lx\n", mstpsr0);
188                 return 0;
189         }
190
191         mstpsr1 = __raw_readl(MSTPSR1);
192         if ((mstpsr1 & 0xff079b7f) != 0xff079b7f) {
193                 pr_debug("sh7372 mstpsr1 0x%08lx\n", mstpsr1);
194                 return 0;
195         }
196
197         mstpsr2 = __raw_readl(MSTPSR2);
198         if ((mstpsr2 & 0x000741ff) != 0x000741ff) {
199                 pr_debug("sh7372 mstpsr2 0x%08lx\n", mstpsr2);
200                 return 0;
201         }
202
203         mstpsr3 = __raw_readl(MSTPSR3);
204         if ((mstpsr3 & 0x1a60f010) != 0x1a60f010) {
205                 pr_debug("sh7372 mstpsr3 0x%08lx\n", mstpsr3);
206                 return 0;
207         }
208
209         mstpsr4 = __raw_readl(MSTPSR4);
210         if ((mstpsr4 & 0x00008cf0) != 0x00008cf0) {
211                 pr_debug("sh7372 mstpsr4 0x%08lx\n", mstpsr4);
212                 return 0;
213         }
214
215         msk = 0;
216         msk2 = 0;
217
218         /* make bitmaps of limited number of wakeup sources */
219
220         if ((mstpsr2 & (1 << 23)) == 0) /* SPU2 */
221                 msk |= 1 << 31;
222
223         if ((mstpsr2 & (1 << 12)) == 0) /* MFI_MFIM */
224                 msk |= 1 << 21;
225
226         if ((mstpsr4 & (1 << 3)) == 0) /* KEYSC */
227                 msk |= 1 << 2;
228
229         if ((mstpsr1 & (1 << 24)) == 0) /* CMT0 */
230                 msk |= 1 << 1;
231
232         if ((mstpsr3 & (1 << 29)) == 0) /* CMT1 */
233                 msk |= 1 << 1;
234
235         if ((mstpsr4 & (1 << 0)) == 0) /* CMT2 */
236                 msk |= 1 << 1;
237
238         if ((mstpsr2 & (1 << 13)) == 0) /* MFI_MFIS */
239                 msk2 |= 1 << 17;
240
241         *mskp = msk;
242         *msk2p = msk2;
243
244         return 1;
245 }
246
247 static void sh7372_icr_to_irqcr(unsigned long icr, u16 *irqcr1p, u16 *irqcr2p)
248 {
249         u16 tmp, irqcr1, irqcr2;
250         int k;
251
252         irqcr1 = 0;
253         irqcr2 = 0;
254
255         /* convert INTCA ICR register layout to SYSC IRQCR+IRQCR2 */
256         for (k = 0; k <= 7; k++) {
257                 tmp = (icr >> ((7 - k) * 4)) & 0xf;
258                 irqcr1 |= (tmp & 0x03) << (k * 2);
259                 irqcr2 |= (tmp >> 2) << (k * 2);
260         }
261
262         *irqcr1p = irqcr1;
263         *irqcr2p = irqcr2;
264 }
265
266 static void sh7372_setup_sysc(unsigned long msk, unsigned long msk2)
267 {
268         u16 irqcrx_low, irqcrx_high, irqcry_low, irqcry_high;
269         unsigned long tmp;
270
271         /* read IRQ0A -> IRQ15A mask */
272         tmp = bitrev8(__raw_readb(INTMSK00A));
273         tmp |= bitrev8(__raw_readb(INTMSK10A)) << 8;
274
275         /* setup WUPSMSK from clocks and external IRQ mask */
276         msk = (~msk & 0xc030000f) | (tmp << 4);
277         __raw_writel(msk, WUPSMSK);
278
279         /* propage level/edge trigger for external IRQ 0->15 */
280         sh7372_icr_to_irqcr(__raw_readl(ICR1A), &irqcrx_low, &irqcry_low);
281         sh7372_icr_to_irqcr(__raw_readl(ICR2A), &irqcrx_high, &irqcry_high);
282         __raw_writel((irqcrx_high << 16) | irqcrx_low, IRQCR);
283         __raw_writel((irqcry_high << 16) | irqcry_low, IRQCR2);
284
285         /* read IRQ16A -> IRQ31A mask */
286         tmp = bitrev8(__raw_readb(INTMSK20A));
287         tmp |= bitrev8(__raw_readb(INTMSK30A)) << 8;
288
289         /* setup WUPSMSK2 from clocks and external IRQ mask */
290         msk2 = (~msk2 & 0x00030000) | tmp;
291         __raw_writel(msk2, WUPSMSK2);
292
293         /* propage level/edge trigger for external IRQ 16->31 */
294         sh7372_icr_to_irqcr(__raw_readl(ICR3A), &irqcrx_low, &irqcry_low);
295         sh7372_icr_to_irqcr(__raw_readl(ICR4A), &irqcrx_high, &irqcry_high);
296         __raw_writel((irqcrx_high << 16) | irqcrx_low, IRQCR3);
297         __raw_writel((irqcry_high << 16) | irqcry_low, IRQCR4);
298 }
299
300 static void sh7372_enter_a3sm_common(int pllc0_on)
301 {
302         /* use INTCA together with SYSC for wakeup */
303         sh7372_setup_sysc(1 << 0, 0);
304         sh7372_set_reset_vector(__pa(sh7372_resume_core_standby_sysc));
305         sh7372_enter_sysc(pllc0_on, 1 << 12);
306 }
307 #endif /* CONFIG_SUSPEND || CONFIG_CPU_IDLE */
308
309 #ifdef CONFIG_CPU_IDLE
310 static int sh7372_do_idle_core_standby(unsigned long unused)
311 {
312         cpu_do_idle(); /* WFI when SYSTBCR == 0x10 -> Core Standby */
313         return 0;
314 }
315
316 static void sh7372_enter_core_standby(void)
317 {
318         sh7372_set_reset_vector(__pa(sh7372_resume_core_standby_sysc));
319
320         /* enter sleep mode with SYSTBCR to 0x10 */
321         __raw_writel(0x10, SYSTBCR);
322         cpu_suspend(0, sh7372_do_idle_core_standby);
323         __raw_writel(0, SYSTBCR);
324
325          /* disable reset vector translation */
326         __raw_writel(0, SBAR);
327 }
328
329 static void sh7372_enter_a3sm_pll_on(void)
330 {
331         sh7372_enter_a3sm_common(1);
332 }
333
334 static void sh7372_enter_a3sm_pll_off(void)
335 {
336         sh7372_enter_a3sm_common(0);
337 }
338
339 static void sh7372_cpuidle_setup(struct cpuidle_driver *drv)
340 {
341         struct cpuidle_state *state = &drv->states[drv->state_count];
342
343         snprintf(state->name, CPUIDLE_NAME_LEN, "C2");
344         strncpy(state->desc, "Core Standby Mode", CPUIDLE_DESC_LEN);
345         state->exit_latency = 10;
346         state->target_residency = 20 + 10;
347         state->flags = CPUIDLE_FLAG_TIME_VALID;
348         shmobile_cpuidle_modes[drv->state_count] = sh7372_enter_core_standby;
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 }
369
370 static void sh7372_cpuidle_init(void)
371 {
372         shmobile_cpuidle_setup = sh7372_cpuidle_setup;
373 }
374 #else
375 static void sh7372_cpuidle_init(void) {}
376 #endif
377
378 #ifdef CONFIG_SUSPEND
379 static 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
388 static int sh7372_enter_suspend(suspend_state_t suspend_state)
389 {
390         unsigned long msk, msk2;
391
392         /* check active clocks to determine potential wakeup sources */
393         if (sh7372_sysc_valid(&msk, &msk2)) {
394                 if (!console_suspend_enabled &&
395                     sh7372_pd_a4s.genpd.status == GPD_STATE_POWER_OFF) {
396                         /* convert INTC mask/sense to SYSC mask/sense */
397                         sh7372_setup_sysc(msk, msk2);
398
399                         /* enter A4S sleep with PLLC0 off */
400                         pr_debug("entering A4S\n");
401                         sh7372_enter_a4s_common(0);
402                         return 0;
403                 }
404         }
405
406         /* default to enter A3SM sleep with PLLC0 off */
407         pr_debug("entering A3SM\n");
408         sh7372_enter_a3sm_common(0);
409         return 0;
410 }
411
412 /**
413  * sh7372_pm_notifier_fn - SH7372 PM notifier routine.
414  * @notifier: Unused.
415  * @pm_event: Event being handled.
416  * @unused: Unused.
417  */
418 static int sh7372_pm_notifier_fn(struct notifier_block *notifier,
419                                  unsigned long pm_event, void *unused)
420 {
421         switch (pm_event) {
422         case PM_SUSPEND_PREPARE:
423                 /*
424                  * This is necessary, because the A4R domain has to be "on"
425                  * when suspend_device_irqs() and resume_device_irqs() are
426                  * executed during system suspend and resume, respectively, so
427                  * that those functions don't crash while accessing the INTCS.
428                  */
429                 pm_genpd_poweron(&sh7372_pd_a4r.genpd);
430                 break;
431         case PM_POST_SUSPEND:
432                 pm_genpd_poweroff_unused();
433                 break;
434         }
435
436         return NOTIFY_DONE;
437 }
438
439 static void sh7372_suspend_init(void)
440 {
441         shmobile_suspend_ops.enter = sh7372_enter_suspend;
442         pm_notifier(sh7372_pm_notifier_fn, 0);
443 }
444 #else
445 static void sh7372_suspend_init(void) {}
446 #endif
447
448 void __init sh7372_pm_init(void)
449 {
450         /* enable DBG hardware block to kick SYSC */
451         __raw_writel(0x0000a500, DBGREG9);
452         __raw_writel(0x0000a501, DBGREG9);
453         __raw_writel(0x00000000, DBGREG1);
454
455         /* do not convert A3SM, A3SP, A3SG, A4R power down into A4S */
456         __raw_writel(0, PDNSEL);
457
458         sh7372_suspend_init();
459         sh7372_cpuidle_init();
460 }