Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/powerpc/platforms/52xx/lite5200_sleep.S
10818 views
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
34
registers:
35
.space 0x5c*4
36
.text
37
38
/* ---------------------------------------------------------------------- */
39
/* low-power mode with help of M68HLC908QT1 */
40
41
.globl lite5200_low_power
42
lite5200_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
81
1:
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
106
sram_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
190
sram_code_end:
191
192
193
194
/* uboot jumps here on resume */
195
lite5200_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
215
mmu_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
272
save_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
337
restore_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
*/
403
flush_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
408
1:
409
lwz r4,0(r3)
410
addi r3,r3,L1_CACHE_BYTES /* Next line, please */
411
bdnz 1b
412
blr
413
414