1#include <linux/init.h>
2#include <linux/suspend.h>
3#include <linux/io.h>
4#include <asm/time.h>
5#include <asm/cacheflush.h>
6#include <asm/mpc52xx.h>
7
8
9extern void mpc52xx_deep_sleep(void __iomem *sram, void __iomem *sdram_regs,
10 struct mpc52xx_cdm __iomem *, struct mpc52xx_intr __iomem*);
11extern void mpc52xx_ds_sram(void);
12extern const long mpc52xx_ds_sram_size;
13extern void mpc52xx_ds_cached(void);
14extern const long mpc52xx_ds_cached_size;
15
16static void __iomem *mbar;
17static void __iomem *sdram;
18static struct mpc52xx_cdm __iomem *cdm;
19static struct mpc52xx_intr __iomem *intr;
20static struct mpc52xx_gpio_wkup __iomem *gpiow;
21static void __iomem *sram;
22static int sram_size;
23
24struct mpc52xx_suspend mpc52xx_suspend;
25
26static int mpc52xx_pm_valid(suspend_state_t state)
27{
28 switch (state) {
29 case PM_SUSPEND_STANDBY:
30 return 1;
31 default:
32 return 0;
33 }
34}
35
36int mpc52xx_set_wakeup_gpio(u8 pin, u8 level)
37{
38 u16 tmp;
39
40
41 out_8(&gpiow->wkup_gpioe, in_8(&gpiow->wkup_gpioe) | (1 << pin));
42
43 out_8(&gpiow->wkup_ddr, in_8(&gpiow->wkup_ddr) & ~(1 << pin));
44
45 out_8(&gpiow->wkup_inten, in_8(&gpiow->wkup_inten) | (1 << pin));
46
47 tmp = in_be16(&gpiow->wkup_itype);
48 tmp &= ~(0x3 << (pin * 2));
49 tmp |= (!level + 1) << (pin * 2);
50 out_be16(&gpiow->wkup_itype, tmp);
51
52 out_8(&gpiow->wkup_maste, 1);
53
54 return 0;
55}
56
57int mpc52xx_pm_prepare(void)
58{
59 struct device_node *np;
60 const struct of_device_id immr_ids[] = {
61 { .compatible = "fsl,mpc5200-immr", },
62 { .compatible = "fsl,mpc5200b-immr", },
63 { .type = "soc", .compatible = "mpc5200", },
64 { .type = "builtin", .compatible = "mpc5200", },
65 {}
66 };
67
68
69 np = of_find_matching_node(NULL, immr_ids);
70 mbar = of_iomap(np, 0);
71 of_node_put(np);
72 if (!mbar) {
73 pr_err("mpc52xx_pm_prepare(): could not map registers\n");
74 return -ENOSYS;
75 }
76
77 sdram = mbar + 0x100;
78 cdm = mbar + 0x200;
79 intr = mbar + 0x500;
80 gpiow = mbar + 0xc00;
81 sram = mbar + 0x8000;
82 sram_size = 0x4000;
83
84
85 if (mpc52xx_suspend.board_suspend_prepare)
86 mpc52xx_suspend.board_suspend_prepare(mbar);
87 else {
88 printk(KERN_ALERT "%s: %i don't know how to wake up the board\n",
89 __func__, __LINE__);
90 goto out_unmap;
91 }
92
93 return 0;
94
95 out_unmap:
96 iounmap(mbar);
97 return -ENOSYS;
98}
99
100
101char saved_sram[0x4000];
102
103int mpc52xx_pm_enter(suspend_state_t state)
104{
105 u32 clk_enables;
106 u32 msr, hid0;
107 u32 intr_main_mask;
108 void __iomem * irq_0x500 = (void __iomem *)CONFIG_KERNEL_START + 0x500;
109 unsigned long irq_0x500_stop = (unsigned long)irq_0x500 + mpc52xx_ds_cached_size;
110 char saved_0x500[mpc52xx_ds_cached_size];
111
112
113 intr_main_mask = in_be32(&intr->main_mask);
114 out_be32(&intr->main_mask, intr_main_mask | 0x1ffff);
115
116
117 mtspr(SPRN_DEC, 0x7fffffff);
118
119
120 memcpy(saved_sram, sram, sram_size);
121
122
123 memcpy(sram, mpc52xx_ds_sram, mpc52xx_ds_sram_size);
124
125 out_8(&cdm->ccs_sleep_enable, 1);
126 out_8(&cdm->osc_sleep_enable, 1);
127 out_8(&cdm->ccs_qreq_test, 1);
128
129
130 clk_enables = in_be32(&cdm->clk_enables);
131 out_be32(&cdm->clk_enables, clk_enables & 0x00088000);
132
133
134 msr = mfmsr();
135 mtmsr(msr & ~MSR_POW);
136
137
138 hid0 = mfspr(SPRN_HID0);
139 mtspr(SPRN_HID0, (hid0 & ~(HID0_DOZE | HID0_NAP | HID0_DPM)) | HID0_SLEEP);
140
141
142 memcpy(saved_0x500, irq_0x500, mpc52xx_ds_cached_size);
143 memcpy(irq_0x500, mpc52xx_ds_cached, mpc52xx_ds_cached_size);
144 flush_icache_range((unsigned long)irq_0x500, irq_0x500_stop);
145
146
147 mpc52xx_deep_sleep(sram, sdram, cdm, intr);
148
149
150 memcpy(irq_0x500, saved_0x500, mpc52xx_ds_cached_size);
151 flush_icache_range((unsigned long)irq_0x500, irq_0x500_stop);
152
153
154 mtmsr(msr & ~MSR_POW);
155 mtspr(SPRN_HID0, hid0);
156 mtmsr(msr);
157
158 out_be32(&cdm->clk_enables, clk_enables);
159 out_8(&cdm->ccs_sleep_enable, 0);
160 out_8(&cdm->osc_sleep_enable, 0);
161
162
163 memcpy(sram, saved_sram, sram_size);
164
165
166 wakeup_decrementer();
167
168
169 out_be32(&intr->main_mask, intr_main_mask);
170
171 return 0;
172}
173
174void mpc52xx_pm_finish(void)
175{
176
177 if (mpc52xx_suspend.board_resume_finish)
178 mpc52xx_suspend.board_resume_finish(mbar);
179
180 iounmap(mbar);
181}
182
183static struct platform_suspend_ops mpc52xx_pm_ops = {
184 .valid = mpc52xx_pm_valid,
185 .prepare = mpc52xx_pm_prepare,
186 .enter = mpc52xx_pm_enter,
187 .finish = mpc52xx_pm_finish,
188};
189
190int __init mpc52xx_pm_init(void)
191{
192 suspend_set_ops(&mpc52xx_pm_ops);
193 return 0;
194}
195