]>
Commit | Line | Data |
---|---|---|
1dbae815 | 1 | /* |
c2d43e39 | 2 | * linux/arch/arm/mach-omap2/sram242x.S |
1dbae815 TL |
3 | * |
4 | * Omap2 specific functions that need to be run in internal SRAM | |
5 | * | |
6 | * (C) Copyright 2004 | |
7 | * Texas Instruments, <www.ti.com> | |
8 | * Richard Woodruff <r-woodruff2@ti.com> | |
9 | * | |
10 | * This program is free software; you can redistribute it and/or | |
11 | * modify it under the terms of the GNU General Public License as | |
12 | * published by the Free Software Foundation; either version 2 of | |
13 | * the License, or (at your option) any later version. | |
14 | * | |
15 | * This program is distributed in the hope that it will be useful, | |
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR /PURPOSE. See the | |
18 | * GNU General Public License for more details. | |
19 | * | |
20 | * You should have received a copy of the GNU General Public License | |
21 | * along with this program; if not, write to the Free Software | |
22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
23 | * MA 02111-1307 USA | |
1124d2f9 PW |
24 | * |
25 | * Richard Woodruff notes that any changes to this code must be carefully | |
26 | * audited and tested to ensure that they don't cause a TLB miss while | |
27 | * the SDRAM is inaccessible. Such a situation will crash the system | |
28 | * since it will cause the ARM MMU to attempt to walk the page tables. | |
29 | * These crashes may be intermittent. | |
1dbae815 | 30 | */ |
1dbae815 | 31 | #include <linux/linkage.h> |
ee0839c2 | 32 | |
1dbae815 | 33 | #include <asm/assembler.h> |
ee0839c2 | 34 | |
dbc04161 | 35 | #include "soc.h" |
ee0839c2 | 36 | #include "iomap.h" |
139563ad | 37 | #include "prm2xxx.h" |
ff4ae5d9 | 38 | #include "cm2xxx.h" |
c2d43e39 | 39 | #include "sdrc.h" |
1dbae815 TL |
40 | |
41 | .text | |
42 | ||
b6338bdc | 43 | .align 3 |
c2d43e39 | 44 | ENTRY(omap242x_sram_ddr_init) |
1dbae815 TL |
45 | stmfd sp!, {r0 - r12, lr} @ save registers on stack |
46 | ||
47 | mov r12, r2 @ capture CS1 vs CS0 | |
48 | mov r8, r3 @ capture force parameter | |
49 | ||
50 | /* frequency shift down */ | |
c2d43e39 | 51 | ldr r2, omap242x_sdi_cm_clksel2_pll @ get address of dpllout reg |
1dbae815 TL |
52 | mov r3, #0x1 @ value for 1x operation |
53 | str r3, [r2] @ go to L1-freq operation | |
54 | ||
55 | /* voltage shift down */ | |
56 | mov r9, #0x1 @ set up for L1 voltage call | |
57 | bl voltage_shift @ go drop voltage | |
58 | ||
59 | /* dll lock mode */ | |
c2d43e39 | 60 | ldr r11, omap242x_sdi_sdrc_dlla_ctrl @ addr of dlla ctrl |
1dbae815 TL |
61 | ldr r10, [r11] @ get current val |
62 | cmp r12, #0x1 @ cs1 base (2422 es2.05/1) | |
63 | addeq r11, r11, #0x8 @ if cs1 base, move to DLLB | |
64 | mvn r9, #0x4 @ mask to get clear bit2 | |
65 | and r10, r10, r9 @ clear bit2 for lock mode. | |
66 | orr r10, r10, #0x8 @ make sure DLL on (es2 bit pos) | |
67 | orr r10, r10, #0x2 @ 90 degree phase for all below 133Mhz | |
68 | str r10, [r11] @ commit to DLLA_CTRL | |
69 | bl i_dll_wait @ wait for dll to lock | |
70 | ||
71 | /* get dll value */ | |
72 | add r11, r11, #0x4 @ get addr of status reg | |
73 | ldr r10, [r11] @ get locked value | |
74 | ||
75 | /* voltage shift up */ | |
76 | mov r9, #0x0 @ shift back to L0-voltage | |
77 | bl voltage_shift @ go raise voltage | |
78 | ||
79 | /* frequency shift up */ | |
80 | mov r3, #0x2 @ value for 2x operation | |
81 | str r3, [r2] @ go to L0-freq operation | |
82 | ||
83 | /* reset entry mode for dllctrl */ | |
84 | sub r11, r11, #0x4 @ move from status to ctrl | |
85 | cmp r12, #0x1 @ normalize if cs1 based | |
86 | subeq r11, r11, #0x8 @ possibly back to DLLA | |
87 | cmp r8, #0x1 @ if forced unlock exit | |
88 | orreq r1, r1, #0x4 @ make sure exit with unlocked value | |
89 | str r1, [r11] @ restore DLLA_CTRL high value | |
90 | add r11, r11, #0x8 @ move to DLLB_CTRL addr | |
91 | str r1, [r11] @ set value DLLB_CTRL | |
92 | bl i_dll_wait @ wait for possible lock | |
93 | ||
94 | /* set up for return, DDR should be good */ | |
95 | str r10, [r0] @ write dll_status and return counter | |
96 | ldmfd sp!, {r0 - r12, pc} @ restore regs and return | |
97 | ||
98 | /* ensure the DLL has relocked */ | |
99 | i_dll_wait: | |
100 | mov r4, #0x800 @ delay DLL relock, min 0x400 L3 clocks | |
101 | i_dll_delay: | |
102 | subs r4, r4, #0x1 | |
103 | bne i_dll_delay | |
6ebbf2ce | 104 | ret lr |
1dbae815 TL |
105 | |
106 | /* | |
107 | * shift up or down voltage, use R9 as input to tell level. | |
108 | * wait for it to finish, use 32k sync counter, 1tick=31uS. | |
109 | */ | |
110 | voltage_shift: | |
c2d43e39 | 111 | ldr r4, omap242x_sdi_prcm_voltctrl @ get addr of volt ctrl. |
1dbae815 TL |
112 | ldr r5, [r4] @ get value. |
113 | ldr r6, prcm_mask_val @ get value of mask | |
114 | and r5, r5, r6 @ apply mask to clear bits | |
115 | orr r5, r5, r9 @ bulld value for L0/L1-volt operation. | |
116 | str r5, [r4] @ set up for change. | |
117 | mov r3, #0x4000 @ get val for force | |
118 | orr r5, r5, r3 @ build value for force | |
119 | str r5, [r4] @ Force transition to L1 | |
120 | ||
c2d43e39 | 121 | ldr r3, omap242x_sdi_timer_32ksynct_cr @ get addr of counter |
1dbae815 TL |
122 | ldr r5, [r3] @ get value |
123 | add r5, r5, #0x3 @ give it at most 93uS | |
124 | volt_delay: | |
125 | ldr r7, [r3] @ get timer value | |
126 | cmp r5, r7 @ time up? | |
127 | bhi volt_delay @ not yet->branch | |
6ebbf2ce | 128 | ret lr @ back to caller. |
1dbae815 | 129 | |
c2d43e39 | 130 | omap242x_sdi_cm_clksel2_pll: |
44595982 | 131 | .word OMAP2420_CM_REGADDR(PLL_MOD, CM_CLKSEL2) |
c2d43e39 | 132 | omap242x_sdi_sdrc_dlla_ctrl: |
44595982 | 133 | .word OMAP242X_SDRC_REGADDR(SDRC_DLLA_CTRL) |
c2d43e39 | 134 | omap242x_sdi_prcm_voltctrl: |
8e3bd351 | 135 | .word OMAP2420_PRCM_VOLTCTRL |
1dbae815 TL |
136 | prcm_mask_val: |
137 | .word 0xFFFF3FFC | |
c2d43e39 | 138 | omap242x_sdi_timer_32ksynct_cr: |
233fd64e | 139 | .word OMAP2_L4_IO_ADDRESS(OMAP2420_32KSYNCT_BASE + 0x010) |
c2d43e39 TL |
140 | ENTRY(omap242x_sram_ddr_init_sz) |
141 | .word . - omap242x_sram_ddr_init | |
1dbae815 TL |
142 | |
143 | /* | |
144 | * Reprograms memory timings. | |
145 | * r0 = [PRCM_FULL | PRCM_HALF] r1 = SDRC_DLLA_CTRL value r2 = [DDR | SDR] | |
146 | * PRCM_FULL = 2, PRCM_HALF = 1, DDR = 1, SDR = 0 | |
147 | */ | |
b6338bdc | 148 | .align 3 |
c2d43e39 | 149 | ENTRY(omap242x_sram_reprogram_sdrc) |
1dbae815 TL |
150 | stmfd sp!, {r0 - r10, lr} @ save registers on stack |
151 | mov r3, #0x0 @ clear for mrc call | |
152 | mcr p15, 0, r3, c7, c10, 4 @ memory barrier, finish ARM SDR/DDR | |
153 | nop | |
154 | nop | |
c2d43e39 | 155 | ldr r6, omap242x_srs_sdrc_rfr_ctrl @ get addr of refresh reg |
1dbae815 TL |
156 | ldr r5, [r6] @ get value |
157 | mov r5, r5, lsr #8 @ isolate rfr field and drop burst | |
158 | ||
159 | cmp r0, #0x1 @ going to half speed? | |
160 | movne r9, #0x0 @ if up set flag up for pre up, hi volt | |
161 | ||
162 | blne voltage_shift_c @ adjust voltage | |
163 | ||
164 | cmp r0, #0x1 @ going to half speed (post branch link) | |
165 | moveq r5, r5, lsr #1 @ divide by 2 if to half | |
166 | movne r5, r5, lsl #1 @ mult by 2 if to full | |
167 | mov r5, r5, lsl #8 @ put rfr field back into place | |
168 | add r5, r5, #0x1 @ turn on burst of 1 | |
c2d43e39 | 169 | ldr r4, omap242x_srs_cm_clksel2_pll @ get address of out reg |
1dbae815 TL |
170 | ldr r3, [r4] @ get curr value |
171 | orr r3, r3, #0x3 | |
172 | bic r3, r3, #0x3 @ clear lower bits | |
173 | orr r3, r3, r0 @ new state value | |
174 | str r3, [r4] @ set new state (pll/x, x=1 or 2) | |
175 | nop | |
176 | nop | |
177 | ||
178 | moveq r9, #0x1 @ if speed down, post down, drop volt | |
179 | bleq voltage_shift_c | |
180 | ||
181 | mcr p15, 0, r3, c7, c10, 4 @ memory barrier | |
182 | str r5, [r6] @ set new RFR_1 value | |
183 | add r6, r6, #0x30 @ get RFR_2 addr | |
184 | str r5, [r6] @ set RFR_2 | |
185 | nop | |
186 | cmp r2, #0x1 @ (SDR or DDR) do we need to adjust DLL | |
187 | bne freq_out @ leave if SDR, no DLL function | |
188 | ||
189 | /* With DDR, we need to take care of the DLL for the frequency change */ | |
c2d43e39 | 190 | ldr r2, omap242x_srs_sdrc_dlla_ctrl @ addr of dlla ctrl |
1dbae815 TL |
191 | str r1, [r2] @ write out new SDRC_DLLA_CTRL |
192 | add r2, r2, #0x8 @ addr to SDRC_DLLB_CTRL | |
193 | str r1, [r2] @ commit to SDRC_DLLB_CTRL | |
194 | mov r1, #0x2000 @ wait DLL relock, min 0x400 L3 clocks | |
195 | dll_wait: | |
196 | subs r1, r1, #0x1 | |
197 | bne dll_wait | |
198 | freq_out: | |
199 | ldmfd sp!, {r0 - r10, pc} @ restore regs and return | |
200 | ||
201 | /* | |
202 | * shift up or down voltage, use R9 as input to tell level. | |
203 | * wait for it to finish, use 32k sync counter, 1tick=31uS. | |
204 | */ | |
205 | voltage_shift_c: | |
c2d43e39 | 206 | ldr r10, omap242x_srs_prcm_voltctrl @ get addr of volt ctrl |
1dbae815 TL |
207 | ldr r8, [r10] @ get value |
208 | ldr r7, ddr_prcm_mask_val @ get value of mask | |
209 | and r8, r8, r7 @ apply mask to clear bits | |
210 | orr r8, r8, r9 @ bulld value for L0/L1-volt operation. | |
211 | str r8, [r10] @ set up for change. | |
212 | mov r7, #0x4000 @ get val for force | |
213 | orr r8, r8, r7 @ build value for force | |
214 | str r8, [r10] @ Force transition to L1 | |
215 | ||
c2d43e39 | 216 | ldr r10, omap242x_srs_timer_32ksynct @ get addr of counter |
1dbae815 TL |
217 | ldr r8, [r10] @ get value |
218 | add r8, r8, #0x2 @ give it at most 62uS (min 31+) | |
219 | volt_delay_c: | |
220 | ldr r7, [r10] @ get timer value | |
221 | cmp r8, r7 @ time up? | |
222 | bhi volt_delay_c @ not yet->branch | |
6ebbf2ce | 223 | ret lr @ back to caller |
1dbae815 | 224 | |
c2d43e39 | 225 | omap242x_srs_cm_clksel2_pll: |
44595982 | 226 | .word OMAP2420_CM_REGADDR(PLL_MOD, CM_CLKSEL2) |
c2d43e39 | 227 | omap242x_srs_sdrc_dlla_ctrl: |
44595982 | 228 | .word OMAP242X_SDRC_REGADDR(SDRC_DLLA_CTRL) |
c2d43e39 | 229 | omap242x_srs_sdrc_rfr_ctrl: |
44595982 | 230 | .word OMAP242X_SDRC_REGADDR(SDRC_RFR_CTRL_0) |
c2d43e39 | 231 | omap242x_srs_prcm_voltctrl: |
8e3bd351 | 232 | .word OMAP2420_PRCM_VOLTCTRL |
1dbae815 TL |
233 | ddr_prcm_mask_val: |
234 | .word 0xFFFF3FFC | |
c2d43e39 | 235 | omap242x_srs_timer_32ksynct: |
233fd64e | 236 | .word OMAP2_L4_IO_ADDRESS(OMAP2420_32KSYNCT_BASE + 0x010) |
1dbae815 | 237 | |
c2d43e39 TL |
238 | ENTRY(omap242x_sram_reprogram_sdrc_sz) |
239 | .word . - omap242x_sram_reprogram_sdrc | |
1dbae815 TL |
240 | |
241 | /* | |
242 | * Set dividers and pll. Also recalculate DLL value for DDR and unlock mode. | |
243 | */ | |
b6338bdc | 244 | .align 3 |
c2d43e39 | 245 | ENTRY(omap242x_sram_set_prcm) |
1dbae815 TL |
246 | stmfd sp!, {r0-r12, lr} @ regs to stack |
247 | adr r4, pbegin @ addr of preload start | |
248 | adr r8, pend @ addr of preload end | |
249 | mcrr p15, 1, r8, r4, c12 @ preload into icache | |
250 | pbegin: | |
251 | /* move into fast relock bypass */ | |
c2d43e39 | 252 | ldr r8, omap242x_ssp_pll_ctl @ get addr |
1dbae815 TL |
253 | ldr r5, [r8] @ get val |
254 | mvn r6, #0x3 @ clear mask | |
255 | and r5, r5, r6 @ clear field | |
256 | orr r7, r5, #0x2 @ fast relock val | |
257 | str r7, [r8] @ go to fast relock | |
c2d43e39 | 258 | ldr r4, omap242x_ssp_pll_stat @ addr of stat |
1dbae815 TL |
259 | block: |
260 | /* wait for bypass */ | |
261 | ldr r8, [r4] @ stat value | |
262 | and r8, r8, #0x3 @ mask for stat | |
263 | cmp r8, #0x1 @ there yet | |
264 | bne block @ loop if not | |
265 | ||
266 | /* set new dpll dividers _after_ in bypass */ | |
c2d43e39 | 267 | ldr r4, omap242x_ssp_pll_div @ get addr |
1dbae815 TL |
268 | str r0, [r4] @ set dpll ctrl val |
269 | ||
c2d43e39 | 270 | ldr r4, omap242x_ssp_set_config @ get addr |
1dbae815 TL |
271 | mov r8, #1 @ valid cfg msk |
272 | str r8, [r4] @ make dividers take | |
273 | ||
274 | mov r4, #100 @ dead spin a bit | |
275 | wait_a_bit: | |
276 | subs r4, r4, #1 @ dec loop | |
277 | bne wait_a_bit @ delay done? | |
278 | ||
279 | /* check if staying in bypass */ | |
280 | cmp r2, #0x1 @ stay in bypass? | |
281 | beq pend @ jump over dpll relock | |
282 | ||
283 | /* relock DPLL with new vals */ | |
c2d43e39 TL |
284 | ldr r5, omap242x_ssp_pll_stat @ get addr |
285 | ldr r4, omap242x_ssp_pll_ctl @ get addr | |
1dbae815 TL |
286 | orr r8, r7, #0x3 @ val for lock dpll |
287 | str r8, [r4] @ set val | |
288 | mov r0, #1000 @ dead spin a bit | |
289 | wait_more: | |
290 | subs r0, r0, #1 @ dec loop | |
291 | bne wait_more @ delay done? | |
292 | wait_lock: | |
293 | ldr r8, [r5] @ get lock val | |
294 | and r8, r8, #3 @ isolate field | |
295 | cmp r8, #2 @ locked? | |
296 | bne wait_lock @ wait if not | |
297 | pend: | |
298 | /* update memory timings & briefly lock dll */ | |
c2d43e39 | 299 | ldr r4, omap242x_ssp_sdrc_rfr @ get addr |
1dbae815 | 300 | str r1, [r4] @ update refresh timing |
c2d43e39 | 301 | ldr r11, omap242x_ssp_dlla_ctrl @ get addr of DLLA ctrl |
1dbae815 TL |
302 | ldr r10, [r11] @ get current val |
303 | mvn r9, #0x4 @ mask to get clear bit2 | |
304 | and r10, r10, r9 @ clear bit2 for lock mode | |
305 | orr r10, r10, #0x8 @ make sure DLL on (es2 bit pos) | |
306 | str r10, [r11] @ commit to DLLA_CTRL | |
307 | add r11, r11, #0x8 @ move to dllb | |
308 | str r10, [r11] @ hit DLLB also | |
309 | ||
310 | mov r4, #0x800 @ relock time (min 0x400 L3 clocks) | |
311 | wait_dll_lock: | |
312 | subs r4, r4, #0x1 | |
313 | bne wait_dll_lock | |
314 | nop | |
315 | ldmfd sp!, {r0-r12, pc} @ restore regs and return | |
316 | ||
c2d43e39 | 317 | omap242x_ssp_set_config: |
8e3bd351 | 318 | .word OMAP2420_PRCM_CLKCFG_CTRL |
c2d43e39 TL |
319 | omap242x_ssp_pll_ctl: |
320 | .word OMAP2420_CM_REGADDR(PLL_MOD, CM_CLKEN) | |
321 | omap242x_ssp_pll_stat: | |
322 | .word OMAP2420_CM_REGADDR(PLL_MOD, CM_IDLEST) | |
323 | omap242x_ssp_pll_div: | |
324 | .word OMAP2420_CM_REGADDR(PLL_MOD, CM_CLKSEL1) | |
325 | omap242x_ssp_sdrc_rfr: | |
44595982 | 326 | .word OMAP242X_SDRC_REGADDR(SDRC_RFR_CTRL_0) |
c2d43e39 | 327 | omap242x_ssp_dlla_ctrl: |
44595982 | 328 | .word OMAP242X_SDRC_REGADDR(SDRC_DLLA_CTRL) |
1dbae815 | 329 | |
c2d43e39 TL |
330 | ENTRY(omap242x_sram_set_prcm_sz) |
331 | .word . - omap242x_sram_set_prcm |