1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
|
/*
* Copyright 2012 Freescale Semiconductor, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#include <linux/linkage.h>
#include <mach/hardware.h>
#include <asm/memory.h>
#include <mach/mvf.h>
#include "regs-src.h"
#include "crm_regs.h"
#define PERIPBASE_VIRT_OFFSET 0xb2000000
#define TTRBIT_MASK 0xffffc000
#define TABLE_INDEX_MASK 0xfff00000
#define TABLE_ENTRY 0x00000c02
#define CACHE_DISABLE_MASK 0xfffffffb
#define IRAM_SUSPEND_SIZE (1 << 15)
/*************************************************************
mvf_suspend:
Suspend the processor (eg, wait for interrupt).
r1: iram_paddr
r2: suspend_iram_base
*************************************************************/
.macro mvf_stop_mode_enter
ldr r3, =MVF_ANATOP_BASE_ADDR
add r3, r3, #PERIPBASE_VIRT_OFFSET
add r3, r3, #0x20000
/* pll7 disable */
ldr r4, [r3, #0x20]
bic r4, r4, #0x2000
str r4, [r3, #0x20]
/* pll3 disable */
ldr r4, [r3, #0x10]
bic r4, r4, #0x2000
str r4, [r3, #0x10]
/* pll4 disable */
ldr r4, [r3, #0x70]
bic r4, r4, #0x2000
str r4, [r3, #0x70]
/* pll6 disable */
ldr r4, [r3, #0xa0]
bic r4, r4, #0x2000
str r4, [r3, #0xa0]
/* pll5 disable */
ldr r4, [r3, #0xe0]
bic r4, r4, #0x2000
str r4, [r3, #0xe0]
/* pll1 disable */
ldr r4, [r3, #0x270]
bic r4, r4, #0x2000
str r4, [r3, #0x270]
/* stop mode is masked to Anatop */
ldr r3, =MVF_CCM_BASE_ADDR
add r3, r3, #PERIPBASE_VIRT_OFFSET
add r3, r3, #0x20000
ldr r4, [r3, #0x2c]
bic r4, r4, #0x100
str r4, [r3, #0x2c]
ldr r3, =MVF_GPC_BASE_ADDR
add r3, r3, #PERIPBASE_VIRT_OFFSET
add r3, r3, #0x20000
/* ensure power domain 0 */
ldr r4, [r3, #0x0]
bic r4, r4, #0x01
str r4, [r3, #0x0]
/* enable deep sleep for memories */
ldr r4, [r3, #0x0]
orr r4, r4, #0x80
str r4, [r3, #0x0]
/* disable well bias */
ldr r4, [r3, #0x0]
bic r4, r4, #0x10
str r4, [r3, #0x0]
/* turn off HPREG in stop mode */
ldr r4, [r3, #0x0]
orr r4, r4, #0x08
str r4, [r3, #0x0]
/* gpc_lpmr set stop mode */
ldr r4, =0x02
str r4, [r3, #0x40]
.endm
.macro mvf_lpstop_mode_enter
ldr r3, =MVF_ANATOP_BASE_ADDR
add r3, r3, #PERIPBASE_VIRT_OFFSET
add r3, r3, #0x20000
/* pll7 disable */
ldr r4, [r3, #0x20]
bic r4, r4, #0x2000
str r4, [r3, #0x20]
/* pll3 disable */
ldr r4, [r3, #0x10]
bic r4, r4, #0x2000
str r4, [r3, #0x10]
/* pll4 disable */
ldr r4, [r3, #0x70]
bic r4, r4, #0x2000
str r4, [r3, #0x70]
/* pll6 disable */
ldr r4, [r3, #0xa0]
bic r4, r4, #0x2000
str r4, [r3, #0xa0]
/* pll5 disable */
ldr r4, [r3, #0xe0]
bic r4, r4, #0x2000
str r4, [r3, #0xe0]
/* pll1 disable */
ldr r4, [r3, #0x270]
bic r4, r4, #0x2000
str r4, [r3, #0x270]
ldr r3, =MVF_CCM_BASE_ADDR
add r3, r3, #PERIPBASE_VIRT_OFFSET
add r3, r3, #0x20000
ldr r4, [r3, #0x2c]
bic r4, r4, #0x100
str r4, [r3, #0x2c]
ldr r3, =MVF_GPC_BASE_ADDR
add r3, r3, #PERIPBASE_VIRT_OFFSET
add r3, r3, #0x20000
/* enable deep sleep for memories */
ldr r4, [r3, #0x0]
orr r4, r4, #0x40
str r4, [r3, #0x0]
/* enable LPSTOP3 */
ldr r4, [r3, #0x0]
bic r4, r4, #0x04
bic r4, r4, #0x02
str r4, [r3, #0x0]
/* ensure power domain 1 */
ldr r4, [r3, #0x0]
orr r4, r4, #0x01
str r4, [r3, #0x0]
/* gpc_lpmr set low-power stop mode */
ldr r4, =0x02
str r4, [r3, #0x40]
.endm
/******************************************************************
Invalidate l1 dcache, r0-r4, r6, r7 used
******************************************************************/
.macro invalidate_l1_dcache
mov r0, #0
mcr p15, 2, r0, c0, c0, 0
mrc p15, 1, r0, c0, c0, 0
ldr r1, =0x7fff
and r2, r1, r0, lsr #13
ldr r1, =0x3ff
and r3, r1, r0, lsr #3 @ NumWays - 1
add r2, r2, #1 @ NumSets
and r0, r0, #0x7
add r0, r0, #4 @ SetShift
clz r1, r3 @ WayShift
add r4, r3, #1 @ NumWays
1:
sub r2, r2, #1 @ NumSets--
mov r3, r4 @ Temp = NumWays
2:
subs r3, r3, #1 @ Temp--
mov r7, r3, lsl r1
mov r6, r2, lsl r0
orr r7, r7, r6
mcr p15, 0, r7, c7, c6, 2
bgt 2b
cmp r2, #0
bgt 1b
dsb
isb
.endm
/******************************************************************
Flush and disable L1 dcache
******************************************************************/
.macro flush_disable_l1_dcache
/*
* Flush all data from the L1 data cache before disabling
* SCTLR.C bit.
*/
push {r0-r12, lr}
ldr r0, =v7_flush_dcache_all
mov lr, pc
mov pc, r0
pop {r0-r12, lr}
/*
* Clear the SCTLR.C bit to prevent further data cache
* allocation. Clearing SCTLR.C would make all the data accesses
* strongly ordered and would not hit the cache.
*/
mrc p15, 0, r0, c1, c0, 0
bic r0, r0, #(1 << 2) @ Disable the C bit
mcr p15, 0, r0, c1, c0, 0
isb
/*
* Invalidate L1 data cache. Even though only invalidate is
* necessary exported flush API is used here. Doing clean
* on already clean cache would be almost NOP.
*/
push {r0-r12, lr}
ldr r0, =v7_flush_dcache_all
mov lr, pc
mov pc, r0
pop {r0-r12, lr}
/*
* Execute an ISB instruction to ensure that all of the
* CP15 register changes have been committed.
*/
isb
/*
* Execute a barrier instruction to ensure that all cache,
* TLB and branch predictor maintenance operations issued
* by any CPU in the cluster have completed.
*/
dsb
dmb
.endm
ENTRY(mvf_suspend)
stmfd sp!, {r0-r12} @ Save registers
/*************************************************************
suspend mode entry
*************************************************************/
mov r11, r0
cmp r0, #0x1
bne dormant
/* Need to flush and disable L1 dcache*/
flush_disable_l1_dcache
wfi
nop
nop
nop
nop
/* Invalidate L1 I-cache first */
mov r1, #0x0
mcr p15, 0, r1, c7, c5, 0 @ Invalidate I-Cache
/* Need to invalidate L1 dcache, as the power is dropped */
invalidate_l1_dcache
/* Enable L1 dcache first */
mrc p15, 0, r0, c1, c0, 0
orr r0, r0, #(1 << 2) @ Disable the C bit
mcr p15, 0, r0, c1, c0, 0
/***********************************************************
never run to here
************************************************************/
b out /* exit standby */
/* Place the literal pool here so that literals are
within 16KB range */
.ltorg
/************************************************************
dormant entry, data save in stack
************************************************************/
dormant:
/************************************************************
saved register and context as below:
sp
spsr
lr
CPACR
TTBR0
TTBR1
TTBCR
DACR
PRRR
NMRR
ACTLR
Context ID
User r/w thread ID
Secure or NS VBAR
CPSR
SCTLR
************************************************************/
/* stack is from the tail of iram_suspend base */
mov r0, r2 /* get suspend_iram_base */
add r0, r0, #IRAM_SUSPEND_SIZE
mov r4, r11 @ Store state entered
stmfd r0!, {r4}
mov r4, sp @ Store sp
mrs r5, spsr @ Store spsr
mov r6, lr @ Store lr
stmfd r0!, {r4-r6}
/* c1 and c2 registers */
mrc p15, 0, r4, c1, c0, 2 @ CPACR
mrc p15, 0, r5, c2, c0, 0 @ TTBR0
mrc p15, 0, r6, c2, c0, 1 @ TTBR1
mrc p15, 0, r7, c2, c0, 2 @ TTBCR
stmfd r0!, {r4-r7}
/* c3 and c10 registers */
mrc p15, 0, r4, c3, c0, 0 @ DACR
mrc p15, 0, r5, c10, c2, 0 @ PRRR
mrc p15, 0, r6, c10, c2, 1 @ NMRR
mrc p15, 0, r7, c1, c0, 1 @ ACTLR
stmfd r0!,{r4-r7}
/* c12, c13 and CPSR registers */
mrc p15, 0, r4, c13, c0, 1 @ Context ID
mrc p15, 0, r5, c13, c0, 2 @ User r/w thread ID
mrc p15, 0, r6, c12, c0, 0 @ Secure or NS VBAR
mrs r7, cpsr @ Store CPSR
stmfd r0!, {r4-r7}
/* c1 control register */
mrc p15, 0, r4, c1, c0, 0 @ SCTLR
stmfd r0!, {r4}
/* Need to flush and disable L1 dcache*/
flush_disable_l1_dcache
/* Make sure TLBs are primed */
ldr r1, =MVF_IOMUXC_BASE_ADDR
add r1, r1, #PERIPBASE_VIRT_OFFSET
add r1, r1, #0x20000
ldr r0, [r1]
ldr r1, =MVF_SRC_BASE_ADDR
add r1, r1, #PERIPBASE_VIRT_OFFSET
add r1, r1, #0x20000
ldr r0, [r1]
ldr r1, =MVF_CCM_BASE_ADDR
add r1, r1, #PERIPBASE_VIRT_OFFSET
add r1, r1, #0x20000
ldr r0, [r1]
ldr r1, =MVF_GPC_BASE_ADDR
add r1, r1, #PERIPBASE_VIRT_OFFSET
add r1, r1, #0x20000
ldr r0, [r1]
ldr r1, =MVF_CCM_BASE_ADDR
add r1, r1, #PERIPBASE_VIRT_OFFSET
add r1, r1, #0x20000
ldr r0, [r1]
/* Do a DSB to drain the buffers */
dsb
mvf_stop_mode_enter
/****************************************************************
execute a wfi instruction to let SOC go into stop mode.
****************************************************************/
wfi
nop
nop
nop
nop
/****************************************************************
if go here, means there is a wakeup irq pending, we should resume
system immediately.
****************************************************************/
mov r0, r2 /* get suspend_iram_base */
add r0, r0, #IRAM_SUSPEND_SIZE
ldmea r0!, {r11} @ standby or mem
/* mask all the GPC interrupts */
ldr r3, =MVF_GPC_BASE_ADDR
add r3, r3, #PERIPBASE_VIRT_OFFSET
add r3, r3, #0x20000
ldr r4, =0xffffffff
str r4, [r3, #0x44]
str r4, [r3, #0x48]
str r4, [r3, #0x4c]
str r4, [r3, #0x50]
/* pll2 enable */
ldr r3, =MVF_ANATOP_BASE_ADDR
add r3, r3, #PERIPBASE_VIRT_OFFSET
add r3, r3, #0x20000
ldr r4, [r3, #0x30]
orr r4, r4, #0x2000
str r4, [r3, #0x30]
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
mrc p15, 0, r1, c1, c0, 0
orr r1, r1, #(1 << 2) @ Enable the C bit
mcr p15, 0, r1, c1, c0, 0
b out
/************************************************
return back to mvf_suspend_enter for suspend
*************************************************/
out:
ldmfd sp!, {r0-r12}
mov pc, lr
.type mvf_do_suspend, #object
ENTRY(mvf_do_suspend)
.word mvf_suspend
.size mvf_suspend, . - mvf_suspend
|