1 | /* |
2 | * SA11x0 Assembler Sleep/WakeUp Management Routines |
3 | * |
4 | * Copyright (c) 2001 Cliff Brake <cbrake@accelent.com> |
5 | * |
6 | * This program is free software; you can redistribute it and/or |
7 | * modify it under the terms of the GNU General Public License. |
8 | * |
9 | * History: |
10 | * |
11 | * 2001-02-06: Cliff Brake Initial code |
12 | * |
13 | * 2001-08-29: Nicolas Pitre Simplified. |
14 | * |
15 | * 2002-05-27: Nicolas Pitre Revisited, more cleanup and simplification. |
16 | * Storage is on the stack now. |
17 | */ |
18 | |
19 | #include <linux/linkage.h> |
20 | #include <asm/assembler.h> |
21 | #include <mach/hardware.h> |
22 | |
23 | .text |
24 | /* |
25 | * sa1100_finish_suspend() |
26 | * |
27 | * Causes sa11x0 to enter sleep state |
28 | * |
29 | * Must be aligned to a cacheline. |
30 | */ |
31 | .balign 32 |
32 | ENTRY(sa1100_finish_suspend) |
33 | @ disable clock switching |
34 | mcr p15, 0, r1, c15, c2, 2 |
35 | |
36 | ldr r6, =MDREFR |
37 | ldr r4, [r6] |
38 | orr r4, r4, #MDREFR_K1DB2 |
39 | ldr r5, =PPCR |
40 | |
41 | @ Pre-load __loop_udelay into the I-cache |
42 | mov r0, #1 |
43 | bl __loop_udelay |
44 | mov r0, r0 |
45 | |
46 | @ The following must all exist in a single cache line to |
47 | @ avoid accessing memory until this sequence is complete, |
48 | @ otherwise we occasionally hang. |
49 | |
50 | @ Adjust memory timing before lowering CPU clock |
51 | str r4, [r6] |
52 | |
53 | @ delay 90us and set CPU PLL to lowest speed |
54 | @ fixes resume problem on high speed SA1110 |
55 | mov r0, #90 |
56 | bl __loop_udelay |
57 | mov r1, #0 |
58 | str r1, [r5] |
59 | mov r0, #90 |
60 | bl __loop_udelay |
61 | |
62 | /* |
63 | * SA1110 SDRAM controller workaround. register values: |
64 | * |
65 | * r0 = &MSC0 |
66 | * r1 = &MSC1 |
67 | * r2 = &MSC2 |
68 | * r3 = MSC0 value |
69 | * r4 = MSC1 value |
70 | * r5 = MSC2 value |
71 | * r6 = &MDREFR |
72 | * r7 = first MDREFR value |
73 | * r8 = second MDREFR value |
74 | * r9 = &MDCNFG |
75 | * r10 = MDCNFG value |
76 | * r11 = third MDREFR value |
77 | * r12 = &PMCR |
78 | * r13 = PMCR value (1) |
79 | */ |
80 | |
81 | ldr r0, =MSC0 |
82 | ldr r1, =MSC1 |
83 | ldr r2, =MSC2 |
84 | |
85 | ldr r3, [r0] |
86 | bic r3, r3, #FMsk(MSC_RT) |
87 | bic r3, r3, #FMsk(MSC_RT)<<16 |
88 | |
89 | ldr r4, [r1] |
90 | bic r4, r4, #FMsk(MSC_RT) |
91 | bic r4, r4, #FMsk(MSC_RT)<<16 |
92 | |
93 | ldr r5, [r2] |
94 | bic r5, r5, #FMsk(MSC_RT) |
95 | bic r5, r5, #FMsk(MSC_RT)<<16 |
96 | |
97 | ldr r7, [r6] |
98 | bic r7, r7, #0x0000FF00 |
99 | bic r7, r7, #0x000000F0 |
100 | orr r8, r7, #MDREFR_SLFRSH |
101 | |
102 | ldr r9, =MDCNFG |
103 | ldr r10, [r9] |
104 | bic r10, r10, #(MDCNFG_DE0+MDCNFG_DE1) |
105 | bic r10, r10, #(MDCNFG_DE2+MDCNFG_DE3) |
106 | |
107 | bic r11, r8, #MDREFR_SLFRSH |
108 | bic r11, r11, #MDREFR_E1PIN |
109 | |
110 | ldr r12, =PMCR |
111 | |
112 | mov r13, #PMCR_SF |
113 | |
114 | b sa1110_sdram_controller_fix |
115 | |
116 | .align 5 |
117 | sa1110_sdram_controller_fix: |
118 | |
119 | @ Step 1 clear RT field of all MSCx registers |
120 | str r3, [r0] |
121 | str r4, [r1] |
122 | str r5, [r2] |
123 | |
124 | @ Step 2 clear DRI field in MDREFR |
125 | str r7, [r6] |
126 | |
127 | @ Step 3 set SLFRSH bit in MDREFR |
128 | str r8, [r6] |
129 | |
130 | @ Step 4 clear DE bis in MDCNFG |
131 | str r10, [r9] |
132 | |
133 | @ Step 5 clear DRAM refresh control register |
134 | str r11, [r6] |
135 | |
136 | @ Wow, now the hardware suspend request pins can be used, that makes them functional for |
137 | @ about 7 ns out of the entire time that the CPU is running! |
138 | |
139 | @ Step 6 set force sleep bit in PMCR |
140 | |
141 | str r13, [r12] |
142 | |
143 | 20: b 20b @ loop waiting for sleep |
144 | |