aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/platforms/52xx
diff options
context:
space:
mode:
authorDomen Puncer <domen.puncer@telargo.com>2007-07-17 16:32:31 -0400
committerPaul Mackerras <paulus@samba.org>2007-09-19 01:25:34 -0400
commitee983079ce04641523b23b8ed02cc3503632351e (patch)
tree3c6b975e47fb38ee51cf3d57e8f5abb1a7699f66 /arch/powerpc/platforms/52xx
parent104f0cc2dcf7ce0ca7da041177233747d6aa0136 (diff)
[POWERPC] MPC5200 low power mode
Low-power mode implementation for Lite5200b. Some I/O registers are also saved here. A recent U-Boot that supports this (lite5200b_PM_config) is needed. Signed-off-by: Domen Puncer <domen.puncer@telargo.com> Signed-off-by: Sylvain Munaut <tnt@246tNt.com> Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch/powerpc/platforms/52xx')
-rw-r--r--arch/powerpc/platforms/52xx/Makefile3
-rw-r--r--arch/powerpc/platforms/52xx/lite5200.c14
-rw-r--r--arch/powerpc/platforms/52xx/lite5200_pm.c213
-rw-r--r--arch/powerpc/platforms/52xx/lite5200_sleep.S412
4 files changed, 637 insertions, 5 deletions
diff --git a/arch/powerpc/platforms/52xx/Makefile b/arch/powerpc/platforms/52xx/Makefile
index b91e39c84d46..307dbc178091 100644
--- a/arch/powerpc/platforms/52xx/Makefile
+++ b/arch/powerpc/platforms/52xx/Makefile
@@ -10,3 +10,6 @@ obj-$(CONFIG_PPC_EFIKA) += efika.o
10obj-$(CONFIG_PPC_LITE5200) += lite5200.o 10obj-$(CONFIG_PPC_LITE5200) += lite5200.o
11 11
12obj-$(CONFIG_PM) += mpc52xx_sleep.o mpc52xx_pm.o 12obj-$(CONFIG_PM) += mpc52xx_sleep.o mpc52xx_pm.o
13ifeq ($(CONFIG_PPC_LITE5200),y)
14 obj-$(CONFIG_PM) += lite5200_sleep.o lite5200_pm.o
15endif
diff --git a/arch/powerpc/platforms/52xx/lite5200.c b/arch/powerpc/platforms/52xx/lite5200.c
index ce3f6951828e..e11d27f9c4f0 100644
--- a/arch/powerpc/platforms/52xx/lite5200.c
+++ b/arch/powerpc/platforms/52xx/lite5200.c
@@ -85,7 +85,6 @@ error:
85} 85}
86 86
87#ifdef CONFIG_PM 87#ifdef CONFIG_PM
88static u32 descr_a;
89static void lite5200_suspend_prepare(void __iomem *mbar) 88static void lite5200_suspend_prepare(void __iomem *mbar)
90{ 89{
91 u8 pin = 1; /* GPIO_WKUP_1 (GPIO_PSC2_4) */ 90 u8 pin = 1; /* GPIO_WKUP_1 (GPIO_PSC2_4) */
@@ -96,13 +95,18 @@ static void lite5200_suspend_prepare(void __iomem *mbar)
96 * power down usb port 95 * power down usb port
97 * this needs to be called before of-ohci suspend code 96 * this needs to be called before of-ohci suspend code
98 */ 97 */
99 descr_a = in_be32(mbar + 0x1048); 98
100 out_be32(mbar + 0x1048, (descr_a & ~0x200) | 0x100); 99 /* set ports to "power switched" and "powered at the same time"
100 * USB Rh descriptor A: NPS = 0, PSM = 0 */
101 out_be32(mbar + 0x1048, in_be32(mbar + 0x1048) & ~0x300);
102 /* USB Rh status: LPS = 1 - turn off power */
103 out_be32(mbar + 0x1050, 0x00000001);
101} 104}
102 105
103static void lite5200_resume_finish(void __iomem *mbar) 106static void lite5200_resume_finish(void __iomem *mbar)
104{ 107{
105 out_be32(mbar + 0x1048, descr_a); 108 /* USB Rh status: LPSC = 1 - turn on power */
109 out_be32(mbar + 0x1050, 0x00010000);
106} 110}
107#endif 111#endif
108 112
@@ -122,7 +126,7 @@ static void __init lite5200_setup_arch(void)
122#ifdef CONFIG_PM 126#ifdef CONFIG_PM
123 mpc52xx_suspend.board_suspend_prepare = lite5200_suspend_prepare; 127 mpc52xx_suspend.board_suspend_prepare = lite5200_suspend_prepare;
124 mpc52xx_suspend.board_resume_finish = lite5200_resume_finish; 128 mpc52xx_suspend.board_resume_finish = lite5200_resume_finish;
125 mpc52xx_pm_init(); 129 lite5200_pm_init();
126#endif 130#endif
127 131
128#ifdef CONFIG_PCI 132#ifdef CONFIG_PCI
diff --git a/arch/powerpc/platforms/52xx/lite5200_pm.c b/arch/powerpc/platforms/52xx/lite5200_pm.c
new file mode 100644
index 000000000000..f26afcd41757
--- /dev/null
+++ b/arch/powerpc/platforms/52xx/lite5200_pm.c
@@ -0,0 +1,213 @@
1#include <linux/init.h>
2#include <linux/pm.h>
3#include <asm/io.h>
4#include <asm/time.h>
5#include <asm/mpc52xx.h>
6#include "mpc52xx_pic.h"
7
8/* defined in lite5200_sleep.S and only used here */
9extern void lite5200_low_power(void __iomem *sram, void __iomem *mbar);
10
11static struct mpc52xx_cdm __iomem *cdm;
12static struct mpc52xx_intr __iomem *pic;
13static struct mpc52xx_sdma __iomem *bes;
14static struct mpc52xx_xlb __iomem *xlb;
15static struct mpc52xx_gpio __iomem *gps;
16static struct mpc52xx_gpio_wkup __iomem *gpw;
17static void __iomem *sram;
18static const int sram_size = 0x4000; /* 16 kBytes */
19static void __iomem *mbar;
20
21static int lite5200_pm_valid(suspend_state_t state)
22{
23 switch (state) {
24 case PM_SUSPEND_STANDBY:
25 case PM_SUSPEND_MEM:
26 return 1;
27 default:
28 return 0;
29 }
30}
31
32static int lite5200_pm_prepare(suspend_state_t state)
33{
34 /* deep sleep? let mpc52xx code handle that */
35 if (state == PM_SUSPEND_STANDBY)
36 return mpc52xx_pm_prepare(state);
37
38 if (state != PM_SUSPEND_MEM)
39 return -EINVAL;
40
41 /* map registers */
42 mbar = mpc52xx_find_and_map("mpc5200");
43 if (!mbar) {
44 printk(KERN_ERR "%s:%i Error mapping registers\n", __func__, __LINE__);
45 return -ENOSYS;
46 }
47
48 cdm = mbar + 0x200;
49 pic = mbar + 0x500;
50 gps = mbar + 0xb00;
51 gpw = mbar + 0xc00;
52 bes = mbar + 0x1200;
53 xlb = mbar + 0x1f00;
54 sram = mbar + 0x8000;
55
56 return 0;
57}
58
59/* save and restore registers not bound to any real devices */
60static struct mpc52xx_cdm scdm;
61static struct mpc52xx_intr spic;
62static struct mpc52xx_sdma sbes;
63static struct mpc52xx_xlb sxlb;
64static struct mpc52xx_gpio sgps;
65static struct mpc52xx_gpio_wkup sgpw;
66
67static void lite5200_save_regs(void)
68{
69 _memcpy_fromio(&spic, pic, sizeof(*pic));
70 _memcpy_fromio(&sbes, bes, sizeof(*bes));
71 _memcpy_fromio(&scdm, cdm, sizeof(*cdm));
72 _memcpy_fromio(&sxlb, xlb, sizeof(*xlb));
73 _memcpy_fromio(&sgps, gps, sizeof(*gps));
74 _memcpy_fromio(&sgpw, gpw, sizeof(*gpw));
75
76 _memcpy_fromio(saved_sram, sram, sram_size);
77}
78
79static void lite5200_restore_regs(void)
80{
81 int i;
82 _memcpy_toio(sram, saved_sram, sram_size);
83
84
85 /*
86 * GPIOs. Interrupt Master Enable has higher address then other
87 * registers, so just memcpy is ok.
88 */
89 _memcpy_toio(gpw, &sgpw, sizeof(*gpw));
90 _memcpy_toio(gps, &sgps, sizeof(*gps));
91
92
93 /* XLB Arbitrer */
94 out_be32(&xlb->snoop_window, sxlb.snoop_window);
95 out_be32(&xlb->master_priority, sxlb.master_priority);
96 out_be32(&xlb->master_pri_enable, sxlb.master_pri_enable);
97
98 /* enable */
99 out_be32(&xlb->int_enable, sxlb.int_enable);
100 out_be32(&xlb->config, sxlb.config);
101
102
103 /* CDM - Clock Distribution Module */
104 out_8(&cdm->ipb_clk_sel, scdm.ipb_clk_sel);
105 out_8(&cdm->pci_clk_sel, scdm.pci_clk_sel);
106
107 out_8(&cdm->ext_48mhz_en, scdm.ext_48mhz_en);
108 out_8(&cdm->fd_enable, scdm.fd_enable);
109 out_be16(&cdm->fd_counters, scdm.fd_counters);
110
111 out_be32(&cdm->clk_enables, scdm.clk_enables);
112
113 out_8(&cdm->osc_disable, scdm.osc_disable);
114
115 out_be16(&cdm->mclken_div_psc1, scdm.mclken_div_psc1);
116 out_be16(&cdm->mclken_div_psc2, scdm.mclken_div_psc2);
117 out_be16(&cdm->mclken_div_psc3, scdm.mclken_div_psc3);
118 out_be16(&cdm->mclken_div_psc6, scdm.mclken_div_psc6);
119
120
121 /* BESTCOMM */
122 out_be32(&bes->taskBar, sbes.taskBar);
123 out_be32(&bes->currentPointer, sbes.currentPointer);
124 out_be32(&bes->endPointer, sbes.endPointer);
125 out_be32(&bes->variablePointer, sbes.variablePointer);
126
127 out_8(&bes->IntVect1, sbes.IntVect1);
128 out_8(&bes->IntVect2, sbes.IntVect2);
129 out_be16(&bes->PtdCntrl, sbes.PtdCntrl);
130
131 for (i=0; i<32; i++)
132 out_8(&bes->ipr[i], sbes.ipr[i]);
133
134 out_be32(&bes->cReqSelect, sbes.cReqSelect);
135 out_be32(&bes->task_size0, sbes.task_size0);
136 out_be32(&bes->task_size1, sbes.task_size1);
137 out_be32(&bes->MDEDebug, sbes.MDEDebug);
138 out_be32(&bes->ADSDebug, sbes.ADSDebug);
139 out_be32(&bes->Value1, sbes.Value1);
140 out_be32(&bes->Value2, sbes.Value2);
141 out_be32(&bes->Control, sbes.Control);
142 out_be32(&bes->Status, sbes.Status);
143 out_be32(&bes->PTDDebug, sbes.PTDDebug);
144
145 /* restore tasks */
146 for (i=0; i<16; i++)
147 out_be16(&bes->tcr[i], sbes.tcr[i]);
148
149 /* enable interrupts */
150 out_be32(&bes->IntPend, sbes.IntPend);
151 out_be32(&bes->IntMask, sbes.IntMask);
152
153
154 /* PIC */
155 out_be32(&pic->per_pri1, spic.per_pri1);
156 out_be32(&pic->per_pri2, spic.per_pri2);
157 out_be32(&pic->per_pri3, spic.per_pri3);
158
159 out_be32(&pic->main_pri1, spic.main_pri1);
160 out_be32(&pic->main_pri2, spic.main_pri2);
161
162 out_be32(&pic->enc_status, spic.enc_status);
163
164 /* unmask and enable interrupts */
165 out_be32(&pic->per_mask, spic.per_mask);
166 out_be32(&pic->main_mask, spic.main_mask);
167 out_be32(&pic->ctrl, spic.ctrl);
168}
169
170static int lite5200_pm_enter(suspend_state_t state)
171{
172 /* deep sleep? let mpc52xx code handle that */
173 if (state == PM_SUSPEND_STANDBY) {
174 return mpc52xx_pm_enter(state);
175 }
176
177 lite5200_save_regs();
178
179 /* effectively save FP regs */
180 enable_kernel_fp();
181
182 lite5200_low_power(sram, mbar);
183
184 lite5200_restore_regs();
185
186 /* restart jiffies */
187 wakeup_decrementer();
188
189 iounmap(mbar);
190 return 0;
191}
192
193static int lite5200_pm_finish(suspend_state_t state)
194{
195 /* deep sleep? let mpc52xx code handle that */
196 if (state == PM_SUSPEND_STANDBY) {
197 return mpc52xx_pm_finish(state);
198 }
199 return 0;
200}
201
202static struct pm_ops lite5200_pm_ops = {
203 .valid = lite5200_pm_valid,
204 .prepare = lite5200_pm_prepare,
205 .enter = lite5200_pm_enter,
206 .finish = lite5200_pm_finish,
207};
208
209int __init lite5200_pm_init(void)
210{
211 pm_set_ops(&lite5200_pm_ops);
212 return 0;
213}
diff --git a/arch/powerpc/platforms/52xx/lite5200_sleep.S b/arch/powerpc/platforms/52xx/lite5200_sleep.S
new file mode 100644
index 000000000000..08ab6fefcf7a
--- /dev/null
+++ b/arch/powerpc/platforms/52xx/lite5200_sleep.S
@@ -0,0 +1,412 @@
1#include <asm/reg.h>
2#include <asm/ppc_asm.h>
3#include <asm/processor.h>
4#include <asm/cache.h>
5
6
7#define SDRAM_CTRL 0x104
8#define SC_MODE_EN (1<<31)
9#define SC_CKE (1<<30)
10#define SC_REF_EN (1<<28)
11#define SC_SOFT_PRE (1<<1)
12
13#define GPIOW_GPIOE 0xc00
14#define GPIOW_DDR 0xc08
15#define GPIOW_DVO 0xc0c
16
17#define CDM_CE 0x214
18#define CDM_SDRAM (1<<3)
19
20
21/* helpers... beware: r10 and r4 are overwritten */
22#define SAVE_SPRN(reg, addr) \
23 mfspr r10, SPRN_##reg; \
24 stw r10, ((addr)*4)(r4);
25
26#define LOAD_SPRN(reg, addr) \
27 lwz r10, ((addr)*4)(r4); \
28 mtspr SPRN_##reg, r10; \
29 sync; \
30 isync;
31
32
33 .data
34registers:
35 .space 0x5c*4
36 .text
37
38/* ---------------------------------------------------------------------- */
39/* low-power mode with help of M68HLC908QT1 */
40
41 .globl lite5200_low_power
42lite5200_low_power:
43
44 mr r7, r3 /* save SRAM va */
45 mr r8, r4 /* save MBAR va */
46
47 /* setup wakeup address for u-boot at physical location 0x0 */
48 lis r3, CONFIG_KERNEL_START@h
49 lis r4, lite5200_wakeup@h
50 ori r4, r4, lite5200_wakeup@l
51 sub r4, r4, r3
52 stw r4, 0(r3)
53
54
55 /*
56 * save stuff BDI overwrites
57 * 0xf0 (0xe0->0x100 gets overwritten when BDI connected;
58 * even when CONFIG_BDI* is disabled and MMU XLAT commented; heisenbug?))
59 * WARNING: self-refresh doesn't seem to work when BDI2000 is connected,
60 * possibly because BDI sets SDRAM registers before wakeup code does
61 */
62 lis r4, registers@h
63 ori r4, r4, registers@l
64 lwz r10, 0xf0(r3)
65 stw r10, (0x1d*4)(r4)
66
67 /* save registers to r4 [destroys r10] */
68 SAVE_SPRN(LR, 0x1c)
69 bl save_regs
70
71 /* flush caches [destroys r3, r4] */
72 bl flush_data_cache
73
74
75 /* copy code to sram */
76 mr r4, r7
77 li r3, (sram_code_end - sram_code)/4
78 mtctr r3
79 lis r3, sram_code@h
80 ori r3, r3, sram_code@l
811:
82 lwz r5, 0(r3)
83 stw r5, 0(r4)
84 addi r3, r3, 4
85 addi r4, r4, 4
86 bdnz 1b
87
88 /* get tb_ticks_per_usec */
89 lis r3, tb_ticks_per_usec@h
90 lwz r11, tb_ticks_per_usec@l(r3)
91
92 /* disable I and D caches */
93 mfspr r3, SPRN_HID0
94 ori r3, r3, HID0_ICE | HID0_DCE
95 xori r3, r3, HID0_ICE | HID0_DCE
96 sync; isync;
97 mtspr SPRN_HID0, r3
98 sync; isync;
99
100 /* jump to sram */
101 mtlr r7
102 blrl
103 /* doesn't return */
104
105
106sram_code:
107 /* self refresh */
108 lwz r4, SDRAM_CTRL(r8)
109
110 /* send NOP (precharge) */
111 oris r4, r4, SC_MODE_EN@h /* mode_en */
112 stw r4, SDRAM_CTRL(r8)
113 sync
114
115 ori r4, r4, SC_SOFT_PRE /* soft_pre */
116 stw r4, SDRAM_CTRL(r8)
117 sync
118 xori r4, r4, SC_SOFT_PRE
119
120 xoris r4, r4, SC_MODE_EN@h /* !mode_en */
121 stw r4, SDRAM_CTRL(r8)
122 sync
123
124 /* delay (for NOP to finish) */
125 li r12, 1
126 bl udelay
127
128 /*
129 * mode_en must not be set when enabling self-refresh
130 * send AR with CKE low (self-refresh)
131 */
132 oris r4, r4, (SC_REF_EN | SC_CKE)@h
133 xoris r4, r4, (SC_CKE)@h /* ref_en !cke */
134 stw r4, SDRAM_CTRL(r8)
135 sync
136
137 /* delay (after !CKE there should be two cycles) */
138 li r12, 1
139 bl udelay
140
141 /* disable clock */
142 lwz r4, CDM_CE(r8)
143 ori r4, r4, CDM_SDRAM
144 xori r4, r4, CDM_SDRAM
145 stw r4, CDM_CE(r8)
146 sync
147
148 /* delay a bit */
149 li r12, 1
150 bl udelay
151
152
153 /* turn off with QT chip */
154 li r4, 0x02
155 stb r4, GPIOW_GPIOE(r8) /* enable gpio_wkup1 */
156 sync
157
158 stb r4, GPIOW_DVO(r8) /* "output" high */
159 sync
160 stb r4, GPIOW_DDR(r8) /* output */
161 sync
162 stb r4, GPIOW_DVO(r8) /* output high */
163 sync
164
165 /* 10uS delay */
166 li r12, 10
167 bl udelay
168
169 /* turn off */
170 li r4, 0
171 stb r4, GPIOW_DVO(r8) /* output low */
172 sync
173
174 /* wait until we're offline */
175 1:
176 b 1b
177
178
179 /* local udelay in sram is needed */
180 udelay: /* r11 - tb_ticks_per_usec, r12 - usecs, overwrites r13 */
181 mullw r12, r12, r11
182 mftb r13 /* start */
183 addi r12, r13, r12 /* end */
184 1:
185 mftb r13 /* current */
186 cmp cr0, r13, r12
187 blt 1b
188 blr
189
190sram_code_end:
191
192
193
194/* uboot jumps here on resume */
195lite5200_wakeup:
196 bl restore_regs
197
198
199 /* HIDs, MSR */
200 LOAD_SPRN(HID1, 0x19)
201 LOAD_SPRN(HID2, 0x1a)
202
203
204 /* address translation is tricky (see turn_on_mmu) */
205 mfmsr r10
206 ori r10, r10, MSR_DR | MSR_IR
207
208
209 mtspr SPRN_SRR1, r10
210 lis r10, mmu_on@h
211 ori r10, r10, mmu_on@l
212 mtspr SPRN_SRR0, r10
213 sync
214 rfi
215mmu_on:
216 /* kernel offset (r4 is still set from restore_registers) */
217 addis r4, r4, CONFIG_KERNEL_START@h
218
219
220 /* restore MSR */
221 lwz r10, (4*0x1b)(r4)
222 mtmsr r10
223 sync; isync;
224
225 /* invalidate caches */
226 mfspr r10, SPRN_HID0
227 ori r5, r10, HID0_ICFI | HID0_DCI
228 mtspr SPRN_HID0, r5 /* invalidate caches */
229 sync; isync;
230 mtspr SPRN_HID0, r10
231 sync; isync;
232
233 /* enable caches */
234 lwz r10, (4*0x18)(r4)
235 mtspr SPRN_HID0, r10 /* restore (enable caches, DPM) */
236 /* ^ this has to be after address translation set in MSR */
237 sync
238 isync
239
240
241 /* restore 0xf0 (BDI2000) */
242 lis r3, CONFIG_KERNEL_START@h
243 lwz r10, (0x1d*4)(r4)
244 stw r10, 0xf0(r3)
245
246 LOAD_SPRN(LR, 0x1c)
247
248
249 blr
250
251
252/* ---------------------------------------------------------------------- */
253/* boring code: helpers */
254
255/* save registers */
256#define SAVE_BAT(n, addr) \
257 SAVE_SPRN(DBAT##n##L, addr); \
258 SAVE_SPRN(DBAT##n##U, addr+1); \
259 SAVE_SPRN(IBAT##n##L, addr+2); \
260 SAVE_SPRN(IBAT##n##U, addr+3);
261
262#define SAVE_SR(n, addr) \
263 mfsr r10, n; \
264 stw r10, ((addr)*4)(r4);
265
266#define SAVE_4SR(n, addr) \
267 SAVE_SR(n, addr); \
268 SAVE_SR(n+1, addr+1); \
269 SAVE_SR(n+2, addr+2); \
270 SAVE_SR(n+3, addr+3);
271
272save_regs:
273 stw r0, 0(r4)
274 stw r1, 0x4(r4)
275 stw r2, 0x8(r4)
276 stmw r11, 0xc(r4) /* 0xc -> 0x5f, (0x18*4-1) */
277
278 SAVE_SPRN(HID0, 0x18)
279 SAVE_SPRN(HID1, 0x19)
280 SAVE_SPRN(HID2, 0x1a)
281 mfmsr r10
282 stw r10, (4*0x1b)(r4)
283 /*SAVE_SPRN(LR, 0x1c) have to save it before the call */
284 /* 0x1d reserved by 0xf0 */
285 SAVE_SPRN(RPA, 0x1e)
286 SAVE_SPRN(SDR1, 0x1f)
287
288 /* save MMU regs */
289 SAVE_BAT(0, 0x20)
290 SAVE_BAT(1, 0x24)
291 SAVE_BAT(2, 0x28)
292 SAVE_BAT(3, 0x2c)
293 SAVE_BAT(4, 0x30)
294 SAVE_BAT(5, 0x34)
295 SAVE_BAT(6, 0x38)
296 SAVE_BAT(7, 0x3c)
297
298 SAVE_4SR(0, 0x40)
299 SAVE_4SR(4, 0x44)
300 SAVE_4SR(8, 0x48)
301 SAVE_4SR(12, 0x4c)
302
303 SAVE_SPRN(SPRG0, 0x50)
304 SAVE_SPRN(SPRG1, 0x51)
305 SAVE_SPRN(SPRG2, 0x52)
306 SAVE_SPRN(SPRG3, 0x53)
307 SAVE_SPRN(SPRG4, 0x54)
308 SAVE_SPRN(SPRG5, 0x55)
309 SAVE_SPRN(SPRG6, 0x56)
310 SAVE_SPRN(SPRG7, 0x57)
311
312 SAVE_SPRN(IABR, 0x58)
313 SAVE_SPRN(DABR, 0x59)
314 SAVE_SPRN(TBRL, 0x5a)
315 SAVE_SPRN(TBRU, 0x5b)
316
317 blr
318
319
320/* restore registers */
321#define LOAD_BAT(n, addr) \
322 LOAD_SPRN(DBAT##n##L, addr); \
323 LOAD_SPRN(DBAT##n##U, addr+1); \
324 LOAD_SPRN(IBAT##n##L, addr+2); \
325 LOAD_SPRN(IBAT##n##U, addr+3);
326
327#define LOAD_SR(n, addr) \
328 lwz r10, ((addr)*4)(r4); \
329 mtsr n, r10;
330
331#define LOAD_4SR(n, addr) \
332 LOAD_SR(n, addr); \
333 LOAD_SR(n+1, addr+1); \
334 LOAD_SR(n+2, addr+2); \
335 LOAD_SR(n+3, addr+3);
336
337restore_regs:
338 lis r4, registers@h
339 ori r4, r4, registers@l
340
341 /* MMU is not up yet */
342 subis r4, r4, CONFIG_KERNEL_START@h
343
344 lwz r0, 0(r4)
345 lwz r1, 0x4(r4)
346 lwz r2, 0x8(r4)
347 lmw r11, 0xc(r4)
348
349 /*
350 * these are a bit tricky
351 *
352 * 0x18 - HID0
353 * 0x19 - HID1
354 * 0x1a - HID2
355 * 0x1b - MSR
356 * 0x1c - LR
357 * 0x1d - reserved by 0xf0 (BDI2000)
358 */
359 LOAD_SPRN(RPA, 0x1e);
360 LOAD_SPRN(SDR1, 0x1f);
361
362 /* restore MMU regs */
363 LOAD_BAT(0, 0x20)
364 LOAD_BAT(1, 0x24)
365 LOAD_BAT(2, 0x28)
366 LOAD_BAT(3, 0x2c)
367 LOAD_BAT(4, 0x30)
368 LOAD_BAT(5, 0x34)
369 LOAD_BAT(6, 0x38)
370 LOAD_BAT(7, 0x3c)
371
372 LOAD_4SR(0, 0x40)
373 LOAD_4SR(4, 0x44)
374 LOAD_4SR(8, 0x48)
375 LOAD_4SR(12, 0x4c)
376
377 /* rest of regs */
378 LOAD_SPRN(SPRG0, 0x50);
379 LOAD_SPRN(SPRG1, 0x51);
380 LOAD_SPRN(SPRG2, 0x52);
381 LOAD_SPRN(SPRG3, 0x53);
382 LOAD_SPRN(SPRG4, 0x54);
383 LOAD_SPRN(SPRG5, 0x55);
384 LOAD_SPRN(SPRG6, 0x56);
385 LOAD_SPRN(SPRG7, 0x57);
386
387 LOAD_SPRN(IABR, 0x58);
388 LOAD_SPRN(DABR, 0x59);
389 LOAD_SPRN(TBWL, 0x5a); /* these two have separate R/W regs */
390 LOAD_SPRN(TBWU, 0x5b);
391
392 blr
393
394
395
396/* cache flushing code. copied from arch/ppc/boot/util.S */
397#define NUM_CACHE_LINES (128*8)
398
399/*
400 * Flush data cache
401 * Do this by just reading lots of stuff into the cache.
402 */
403flush_data_cache:
404 lis r3,CONFIG_KERNEL_START@h
405 ori r3,r3,CONFIG_KERNEL_START@l
406 li r4,NUM_CACHE_LINES
407 mtctr r4
4081:
409 lwz r4,0(r3)
410 addi r3,r3,L1_CACHE_BYTES /* Next line, please */
411 bdnz 1b
412 blr