summaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-sa1100/sleep.S
blob: 04f2a618d4ef11b20976ecc3eb141e10835f4aa9 (plain)
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
/*
 * SA11x0 Assembler Sleep/WakeUp Management Routines
 *
 * Copyright (c) 2001 Cliff Brake <cbrake@accelent.com>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License.
 *
 * History:
 *
 * 2001-02-06: Cliff Brake         Initial code
 *
 * 2001-08-29:	Nicolas Pitre	Simplified.
 *
 * 2002-05-27:	Nicolas Pitre	Revisited, more cleanup and simplification.
 *				Storage is on the stack now.
 */

#include <linux/linkage.h>
#include <asm/assembler.h>
#include <mach/hardware.h>

		.text
/*
 * sa1100_cpu_suspend()
 *
 * Causes sa11x0 to enter sleep state
 *
 */

ENTRY(sa1100_cpu_suspend)
	stmfd	sp!, {r4 - r12, lr}		@ save registers on stack
	mov	r1, r0
	ldr	r3, =sa1100_cpu_resume		@ return function
	bl	cpu_suspend

	@ disable clock switching
	mcr	p15, 0, r1, c15, c2, 2

        @ Adjust memory timing before lowering CPU clock
	@ Clock speed adjustment without changing memory timing makes
	@ CPU hang in some cases
        ldr     r0, =MDREFR
        ldr     r1, [r0]
        orr     r1, r1, #MDREFR_K1DB2
        str     r1, [r0]

	@ delay 90us and set CPU PLL to lowest speed
	@ fixes resume problem on high speed SA1110
	mov	r0, #90
	bl	__udelay
	ldr	r0, =PPCR
	mov	r1, #0
	str	r1, [r0]
	mov	r0, #90
	bl	__udelay

	/*
	 * SA1110 SDRAM controller workaround.  register values:
	 *
	 * r0  = &MSC0
	 * r1  = &MSC1
	 * r2  = &MSC2
	 * r3  = MSC0 value
	 * r4  = MSC1 value
	 * r5  = MSC2 value
	 * r6  = &MDREFR
	 * r7  = first MDREFR value
	 * r8  = second MDREFR value
	 * r9  = &MDCNFG
	 * r10 = MDCNFG value
	 * r11 = third MDREFR value
	 * r12 = &PMCR
	 * r13 = PMCR value (1)
	 */

	ldr	r0, =MSC0
	ldr	r1, =MSC1
	ldr	r2, =MSC2

	ldr	r3, [r0]
	bic	r3, r3, #FMsk(MSC_RT)
	bic	r3, r3, #FMsk(MSC_RT)<<16

	ldr	r4, [r1]
	bic	r4, r4, #FMsk(MSC_RT)
	bic	r4, r4, #FMsk(MSC_RT)<<16

	ldr	r5, [r2]
	bic	r5, r5, #FMsk(MSC_RT)
	bic	r5, r5, #FMsk(MSC_RT)<<16

	ldr	r6, =MDREFR

	ldr	r7, [r6]
bic	r7, r7, #0x0000FF00
bic	r7, r7, #0x000000F0
orr	r8, r7, #MDREFR_SLFRSH

	ldr	r9, =MDCNFG
	ldr	r10, [r9]
	bic	r10, r10, #(MDCNFG_DE0+MDCNFG_DE1)
	bic	r10, r10, #(MDCNFG_DE2+MDCNFG_DE3)

	bic	r11, r8, #MDREFR_SLFRSH
	bic	r11, r11, #MDREFR_E1PIN

	ldr	r12, =PMCR

	mov	r13, #PMCR_SF

	b	sa1110_sdram_controller_fix

	.align 5
sa1110_sdram_controller_fix:

	@ Step 1 clear RT field of all MSCx registers
	str 	r3, [r0]
	str	r4, [r1]
	str	r5, [r2]

	@ Step 2 clear DRI field in MDREFR
	str	r7, [r6]

	@ Step 3 set SLFRSH bit in MDREFR
	str	r8, [r6]

	@ Step 4 clear DE bis in MDCNFG
	str	r10, [r9]

	@ Step 5 clear DRAM refresh control register
	str	r11, [r6]

	@ Wow, now the hardware suspend request pins can be used, that makes them functional for
	@ about 7 ns out of the	entire time that the CPU is running!

	@ Step 6 set force sleep bit in PMCR

	str	r13, [r12]

20:	b	20b			@ loop waiting for sleep

/*
 * cpu_sa1100_resume()
 *
 * entry point from bootloader into kernel during resume
 */
	.align 5
sa1100_cpu_resume:
	mcr	p15, 0, r1, c15, c1, 2		@ enable clock switching
	ldmfd	sp!, {r4 - r12, pc}		@ return to caller