]> git.karo-electronics.de Git - karo-tx-linux.git/blob - arch/arm/mach-imx/ddr3_freq_imx6.S
ENGR00297285-1 [MX6x] Support IRAM page table when DDR is in self-refresh.
[karo-tx-linux.git] / arch / arm / mach-imx / ddr3_freq_imx6.S
1 /*
2  * Copyright (C) 2011-2014 Freescale Semiconductor, Inc. All Rights Reserved.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17  */
18
19 #include <linux/linkage.h>
20 #include "hardware.h"
21
22 #define MMDC0_MDPDC             0x4
23 #define MMDC0_MDCF0                     0x0c
24 #define MMDC0_MDCF1                     0x10
25 #define MMDC0_MDMISC            0x18
26 #define MMDC0_MDSCR             0x1c
27 #define MMDC0_MAPSR                     0x404
28 #define MMDC0_MADPCR0           0x410
29 #define MMDC0_MPZQHWCTRL        0x800
30 #define MMDC1_MPZQHWCTRL        0x4800
31 #define MMDC0_MPODTCTRL 0x818
32 #define MMDC1_MPODTCTRL 0x4818
33 #define MMDC0_MPDGCTRL0 0x83c
34 #define MMDC1_MPDGCTRL0 0x483c
35 #define MMDC0_MPMUR0            0x8b8
36 #define MMDC1_MPMUR0            0x48b8
37
38 #define CCM_CBCDR                       0x14
39 #define CCM_CBCMR                       0x18
40 #define CCM_CSCMR1                      0x1c
41 #define CCM_CDHIPR                      0x48
42
43 #define L2_CACHE_SYNC           0x730
44
45 .extern iram_tlb_phys_addr
46
47         .align 3
48
49         .macro  switch_to_528MHz
50
51         /* check if periph_clk_sel is already set */
52         ldr     r0, [r6, #CCM_CBCDR]
53         and     r0, r0, #(1 << 25)
54         cmp     r0, #(1 << 25)
55         beq     set_ahb_podf_before_switch
56
57         /* change periph_clk to be sourced from pll3_clk. */
58         ldr     r0, [r6, #CCM_CBCMR]
59         bic     r0, r0, #(3 << 12)
60         str     r0, [r6, #CCM_CBCMR]
61
62         ldr     r0, [r6, #CCM_CBCDR]
63         bic     r0, r0, #(0x38 << 20)
64         str     r0, [r6, #CCM_CBCDR]
65
66         /*
67          * set the AHB dividers before the switch,
68          * don't change AXI clock divider,
69          * set the MMDC_DIV=1, AXI_DIV = 2, AHB_DIV=4,
70          */
71         ldr     r0, [r6, #CCM_CBCDR]
72         ldr     r2, =0x3f1f00
73         bic     r0, r0, r2
74         orr     r0, r0, #0xd00
75         orr     r0, r0, #(1 << 16)
76         str     r0, [r6, #CCM_CBCDR]
77
78 wait_div_update528:
79         ldr     r0, [r6, #CCM_CDHIPR]
80         cmp     r0, #0
81         bne     wait_div_update528
82
83         /* now switch periph_clk to pll3_main_clk. */
84         ldr     r0, [r6, #CCM_CBCDR]
85         orr     r0, r0, #(1 << 25)
86         str     r0, [r6, #CCM_CBCDR]
87
88 periph_clk_switch3:
89         ldr     r0, [r6, #CCM_CDHIPR]
90         cmp     r0, #0
91         bne     periph_clk_switch3
92
93         b       switch_pre_periph_clk_528
94
95 set_ahb_podf_before_switch:
96         /*
97          * set the MMDC_DIV=1, AXI_DIV = 2, AHB_DIV=4,
98          */
99         ldr     r0, [r6, #CCM_CBCDR]
100         ldr     r2, =0x3f1f00
101         bic     r0, r0, r2
102         orr     r0, r0, #0xd00
103         orr     r0, r0, #(1 << 16)
104         str     r0, [r6, #CCM_CBCDR]
105
106 wait_div_update528_1:
107         ldr     r0, [r6, #CCM_CDHIPR]
108         cmp     r0, #0
109         bne     wait_div_update528_1
110
111 switch_pre_periph_clk_528:
112
113         /* now switch pre_periph_clk to PLL2_528MHz. */
114         ldr     r0, [r6, #CCM_CBCMR]
115         bic     r0, r0, #(0xc << 16)
116         str     r0, [r6, #CCM_CBCMR]
117
118         /* now switch periph_clk back. */
119         ldr     r0, [r6, #CCM_CBCDR]
120         bic     r0, r0, #(1 << 25)
121         str     r0, [r6, #CCM_CBCDR]
122
123 periph_clk_switch4:
124         ldr     r0, [r6, #CCM_CDHIPR]
125         cmp     r0, #0
126         bne     periph_clk_switch4
127
128         .endm
129
130         .macro  switch_to_400MHz
131
132         /* check if periph_clk_sel is already set. */
133         ldr     r0, [r6, #CCM_CBCDR]
134         and     r0, r0, #(1 << 25)
135         cmp     r0, #(1 << 25)
136         beq     set_ahb_podf_before_switch1
137
138         /* change periph_clk to be sourced from pll3_clk. */
139         ldr     r0, [r6, #CCM_CBCMR]
140         bic     r0, r0, #(3 << 12)
141         str     r0, [r6, #CCM_CBCMR]
142
143         ldr     r0, [r6, #CCM_CBCDR]
144         bic     r0, r0, #(0x38 << 24)
145         str     r0, [r6, #CCM_CBCDR]
146
147         /* now switch periph_clk to pll3_main_clk. */
148         ldr     r0, [r6, #CCM_CBCDR]
149         orr     r0, r0, #(1 << 25)
150         str     r0, [r6, #CCM_CBCDR]
151
152 periph_clk_switch5:
153         ldr     r0, [r6, #CCM_CDHIPR]
154         cmp     r0, #0
155         bne     periph_clk_switch5
156
157         b       switch_pre_periph_clk_400
158
159 set_ahb_podf_before_switch1:
160         /*
161          * set the MMDC_DIV=1, AXI_DIV = 2, AHB_DIV=4,
162          */
163         ldr     r0, [r6, #CCM_CBCDR]
164         ldr     r2, =0x3f1f00
165         bic     r0, r0, r2
166         orr     r0, r0, #(0x9 << 8)
167         orr     r0, r0, #(1 << 16)
168         str     r0, [r6, #CCM_CBCDR]
169
170 wait_div_update400_1:
171         ldr     r0, [r6, #CCM_CDHIPR]
172         cmp     r0, #0
173         bne     wait_div_update400_1
174
175 switch_pre_periph_clk_400:
176
177         /* now switch pre_periph_clk to PFD_400MHz. */
178         ldr     r0, [r6, #CCM_CBCMR]
179         bic     r0, r0, #(0xc << 16)
180         orr     r0, r0, #(0x4 << 16)
181         str     r0, [r6, #CCM_CBCMR]
182
183         /* now switch periph_clk back. */
184         ldr     r0, [r6, #CCM_CBCDR]
185         bic     r0, r0, #(1 << 25)
186         str     r0, [r6, #CCM_CBCDR]
187
188 periph_clk_switch6:
189         ldr     r0, [r6, #CCM_CDHIPR]
190         cmp     r0, #0
191         bne     periph_clk_switch6
192
193         /*
194          * change AHB divider so that we are at 400/3=133MHz.
195          * don't change AXI clock divider.
196          * set the MMDC_DIV=1, AXI_DIV=2, AHB_DIV=3,
197          */
198         ldr     r0, [r6, #CCM_CBCDR]
199         ldr     r2, =0x3f1f00
200         bic     r0, r0, r2
201         orr     r0, r0, #(0x9 << 8)
202         orr     r0, r0, #(1 << 16)
203         str     r0, [r6, #CCM_CBCDR]
204
205 wait_div_update400_2:
206         ldr     r0, [r6, #CCM_CDHIPR]
207         cmp     r0, #0
208         bne     wait_div_update400_2
209
210         .endm
211
212         .macro  switch_to_50MHz
213
214         /* check if periph_clk_sel is already set. */
215         ldr     r0, [r6, #CCM_CBCDR]
216         and     r0, r0, #(1 << 25)
217         cmp     r0, #(1 << 25)
218         beq     switch_pre_periph_clk_50
219
220         /*
221          * set the periph_clk to be sourced from PLL2_PFD_200M
222          * change periph_clk to be sourced from pll3_clk.
223          * ensure PLL3 is the source and set the divider to 1.
224          */
225         ldr     r0, [r6, #CCM_CBCMR]
226         bic     r0, r0, #(0x3 << 12)
227         str     r0, [r6, #CCM_CBCMR]
228
229         ldr     r0, [r6, #CCM_CBCDR]
230         bic     r0, r0, #(0x38 << 24)
231         str     r0, [r6, #CCM_CBCDR]
232
233         /* now switch periph_clk to pll3_main_clk. */
234         ldr     r0, [r6, #CCM_CBCDR]
235         orr     r0, r0, #(1 << 25)
236         str     r0, [r6, #CCM_CBCDR]
237
238 periph_clk_switch_50:
239         ldr     r0, [r6, #CCM_CDHIPR]
240         cmp     r0, #0
241         bne     periph_clk_switch_50
242
243 switch_pre_periph_clk_50:
244
245         /* now switch pre_periph_clk to PFD_200MHz. */
246         ldr     r0, [r6, #CCM_CBCMR]
247         orr     r0, r0, #(0xc << 16)
248         str     r0, [r6, #CCM_CBCMR]
249
250         /*
251          * set the MMDC_DIV=4, AXI_DIV = 4, AHB_DIV=8,
252          */
253         ldr     r0, [r6, #CCM_CBCDR]
254         ldr     r2, =0x3f1f00
255         bic     r0, r0, r2
256         orr     r0, r0, #(0x18 << 16)
257         orr     r0, r0, #(0x3 << 16)
258
259         /*
260          * if changing AHB divider remember to change
261          * the IPGPER divider too below.
262          */
263         orr     r0, r0, #0x1d00
264         str     r0, [r6, #CCM_CBCDR]
265
266 wait_div_update_50:
267         ldr     r0, [r6, #CCM_CDHIPR]
268         cmp     r0, #0
269         bne     wait_div_update_50
270
271         /* now switch periph_clk back. */
272         ldr     r0, [r6, #CCM_CBCDR]
273         bic     r0, r0, #(1 << 25)
274         str     r0, [r6, #CCM_CBCDR]
275
276 periph_clk_switch2:
277         ldr     r0, [r6, #CCM_CDHIPR]
278         cmp     r0, #0
279         bne     periph_clk_switch2
280
281         .endm
282
283         .macro  switch_to_24MHz
284         /*
285          * change the freq now try setting DDR to 24MHz.
286          * source it from the periph_clk2 ensure the
287          * periph_clk2 is sourced from 24MHz and the
288          * divider is 1.
289          */
290
291         ldr     r0, [r6, #CCM_CBCMR]
292         bic     r0, r0, #(0x3 << 12)
293         orr     r0, r0, #(1 << 12)
294         str     r0, [r6, #CCM_CBCMR]
295
296         ldr     r0, [r6, #CCM_CBCDR]
297         bic     r0, r0, #(0x38 << 24)
298         str     r0, [r6, #CCM_CBCDR]
299
300         /* now switch periph_clk to 24MHz. */
301         ldr     r0, [r6, #CCM_CBCDR]
302         orr     r0, r0, #(1 << 25)
303         str     r0, [r6, #CCM_CBCDR]
304
305 periph_clk_switch1:
306         ldr     r0, [r6, #CCM_CDHIPR]
307         cmp     r0, #0
308         bne     periph_clk_switch1
309
310         /* change all the dividers to 1. */
311         ldr     r0, [r6, #CCM_CBCDR]
312         ldr     r2, =0x3f1f00
313         bic     r0, r0, r2
314         orr     r0, r0, #(1 << 8)
315         str     r0, [r6, #CCM_CBCDR]
316
317         /* Wait for the divider to change. */
318 wait_div_update:
319         ldr     r0, [r6, #CCM_CDHIPR]
320         cmp     r0, #0
321         bne     wait_div_update
322
323         .endm
324
325 /*
326  *  mx6_ddr3_freq_change
327  *
328  *  idle the processor (eg, wait for interrupt).
329  *  make sure DDR is in self-refresh.
330  *  IRQs are already disabled.
331  */
332 ENTRY(mx6_ddr3_freq_change)
333
334         stmfd   sp!, {r4-r12}
335
336         /*
337          * r5 -> mmdc_base
338          * r6 -> ccm_base
339          * r7 -> iomux_base
340          * r12 -> l2_base
341          */
342         mov     r4, r0
343         mov     r8, r1
344         mov     r9, r2
345         mov     r11, r3
346
347 ddr_freq_change:
348         /*
349          * To ensure no page table walks occur in DDR, we
350          * have a another page table stored in IRAM that only
351          * contains entries pointing to IRAM, AIPS1 and AIPS2.
352          * We need to set the TTBR1 to the new IRAM TLB.
353          * Do the following steps:
354          * 1. Flush the Branch Target Address Cache (BTAC)
355          * 2. Set TTBR1 to point to IRAM page table.
356          * 3. Disable page table walks in TTBR0 (PD0 = 1)
357          * 4. Set TTBR0.N=1, implying 0-2G is translated by TTBR0
358          *     and 2-4G is translated by TTBR1.
359          */
360
361         /* Flush the Branch Target Address Cache (BTAC) */
362         ldr     r6, =0x0
363         mcr     p15, 0, r6, c7, c1, 6
364         ldr     r6, =iram_tlb_phys_addr
365         ldr     r6, [r6]
366         dsb
367         isb
368         /* Store the IRAM table in TTBR1 */
369         mcr     p15, 0, r6, c2, c0, 1
370
371         /* Read TTBCR and set PD0=1, N = 1 */
372         mrc     p15, 0, r6, c2, c0, 2
373         orr     r6, r6, #0x11
374         mcr     p15, 0, r6, c2, c0, 2
375
376         dsb
377         isb
378
379         /* flush the TLB */
380         ldr     r6, =0x0
381         mcr     p15, 0, r6, c8, c3, 0
382         dsb
383         isb
384
385         ldr     r5, =IMX_IO_P2V(MX6Q_MMDC_P0_BASE_ADDR)
386         ldr     r6, =IMX_IO_P2V(MX6Q_CCM_BASE_ADDR)
387         ldr     r7, =IMX_IO_P2V(MX6Q_IOMUXC_BASE_ADDR)
388         ldr     r12, =IMX_IO_P2V(MX6Q_L2_BASE_ADDR)
389
390 #ifdef CONFIG_CACHE_L2X0
391         /*
392           * Make sure the L2 buffers are drained.
393           * Sync operation on L2 drains the buffers.
394           */
395         mov    r1, #0x0
396         str      r1, [r12, #L2_CACHE_SYNC]
397 #endif
398
399         /* disable automatic power saving. */
400         ldr     r0, [r5, #MMDC0_MAPSR]
401         orr     r0, r0, #0x01
402         str     r0, [r5, #MMDC0_MAPSR]
403
404         /* disable MMDC power down timer. */
405         ldr     r0, [r5, #MMDC0_MDPDC]
406         bic     r0, r0, #(0xff << 8)
407         str     r0, [r5, #MMDC0_MDPDC]
408
409         /* delay for a while */
410         ldr     r1, =4
411 delay1:
412         ldr     r2, =0
413 cont1:
414         ldr     r0, [r5, r2]
415         add     r2, r2, #4
416         cmp     r2, #16
417         bne     cont1
418         sub     r1, r1, #1
419         cmp     r1, #0
420         bgt     delay1
421
422         /* set CON_REG */
423         ldr     r0, =0x8000
424         str     r0, [r5, #MMDC0_MDSCR]
425 poll_conreq_set_1:
426         ldr     r0, [r5, #MMDC0_MDSCR]
427         and     r0, r0, #(0x4 << 12)
428         cmp     r0, #(0x4 << 12)
429         bne     poll_conreq_set_1
430
431         ldr     r0, =0x00008010
432         str     r0, [r5, #MMDC0_MDSCR]
433         ldr     r0, =0x00008018
434         str     r0, [r5, #MMDC0_MDSCR]
435
436         /*
437          * if requested frequency is greater than
438          * 300MHz go to DLL on mode.
439          */
440         ldr     r1, =300000000
441         cmp     r4, r1
442         bge     dll_on_mode
443
444 dll_off_mode:
445
446         /* if DLL is currently on, turn it off. */
447         cmp     r9, #1
448         beq     continue_dll_off_1
449
450         ldr     r0, =0x00018031
451         str     r0, [r5, #MMDC0_MDSCR]
452
453         ldr     r0, =0x00018039
454         str     r0, [r5, #MMDC0_MDSCR]
455
456         ldr     r1, =10
457 delay1a:
458         ldr     r2, =0
459 cont1a:
460         ldr     r0, [r5, r2]
461         add     r2, r2, #4
462         cmp     r2, #16
463         bne     cont1a
464         sub     r1, r1, #1
465         cmp     r1, #0
466         bgt     delay1a
467
468 continue_dll_off_1:
469         /* set DVFS - enter self refresh mode */
470         ldr     r0, [r5, #MMDC0_MAPSR]
471         orr     r0, r0, #(1 << 21)
472         str     r0, [r5, #MMDC0_MAPSR]
473
474         /* de-assert con_req */
475         mov     r0, #0x0
476         str     r0, [r5, #MMDC0_MDSCR]
477
478 poll_dvfs_set_1:
479         ldr     r0, [r5, #MMDC0_MAPSR]
480         and     r0, r0, #(1 << 25)
481         cmp     r0, #(1 << 25)
482         bne     poll_dvfs_set_1
483
484         ldr     r1, =24000000
485         cmp     r4, r1
486         beq     switch_freq_24
487
488         switch_to_50MHz
489         b       continue_dll_off_2
490
491 switch_freq_24:
492         switch_to_24MHz
493
494 continue_dll_off_2:
495
496         /* set SBS - block ddr accesses */
497         ldr     r0, [r5, #MMDC0_MADPCR0]
498         orr     r0, r0, #(1 << 8)
499         str     r0, [r5, #MMDC0_MADPCR0]
500
501         /* clear DVFS - exit from self refresh mode */
502         ldr     r0, [r5, #MMDC0_MAPSR]
503         bic     r0, r0, #(1 << 21)
504         str     r0, [r5, #MMDC0_MAPSR]
505
506 poll_dvfs_clear_1:
507         ldr     r0, [r5, #MMDC0_MAPSR]
508         and     r0, r0, #(1 << 25)
509         cmp     r0, #(1 << 25)
510         beq     poll_dvfs_clear_1
511
512         /* if DLL was previously on, continue DLL off routine. */
513         cmp     r9, #1
514         beq     continue_dll_off_3
515
516         ldr     r0, =0x00018031
517         str     r0, [r5, #MMDC0_MDSCR]
518
519         ldr     r0, =0x00018039
520         str     r0, [r5, #MMDC0_MDSCR]
521
522         ldr     r0, =0x08208030
523         str     r0, [r5, #MMDC0_MDSCR]
524
525         ldr     r0, =0x08208038
526         str     r0, [r5, #MMDC0_MDSCR]
527
528         ldr     r0, =0x00088032
529         str     r0, [r5, #MMDC0_MDSCR]
530
531         ldr     r0, =0x0008803A
532         str     r0, [r5, #MMDC0_MDSCR]
533
534         /* delay for a while. */
535         ldr     r1, =4
536 delay_1:
537         ldr     r2, =0
538 cont_1:
539         ldr     r0, [r5, r2]
540         add     r2, r2, #4
541         cmp     r2, #16
542         bne     cont_1
543         sub     r1, r1, #1
544         cmp     r1, #0
545         bgt     delay_1
546
547         ldr     r0, [r5, #MMDC0_MDCF0]
548         bic     r0, r0, #0xf
549         orr     r0, r0, #0x3
550         str     r0, [r5, #MMDC0_MDCF0]
551
552         ldr     r0, [r5, #MMDC0_MDCF1]
553         bic     r0, r0, #0x7
554         orr     r0, r0, #0x4
555         str     r0, [r5, #MMDC0_MDCF1]
556
557         ldr     r0, =0x00091680
558         str     r0, [r5, #MMDC0_MDMISC]
559
560         /* enable dqs pull down in the IOMUX. */
561         ldr     r1, [r11]
562         add     r11, r11, #8
563         ldr     r2, =0x3028
564 update_iomux:
565         ldr     r0, [r11, #0x0]
566         ldr     r3, [r7, r0]
567         bic     r3, r3, r2
568         orr     r3, r3, #(0x3 << 12)
569         orr     r3, r3, #0x28
570         str     r3, [r7, r0]
571         add     r11, r11, #8
572         sub     r1, r1, #1
573         cmp     r1, #0
574         bgt     update_iomux
575
576         /*  ODT disabled. */
577         ldr     r0, =0x0
578         ldr     r2, =MMDC0_MPODTCTRL
579         str     r0, [r5, r2]
580         ldr     r2, =MMDC1_MPODTCTRL
581         str     r0, [r5, r2]
582
583         /* DQS gating disabled. */
584         ldr     r2, =MMDC0_MPDGCTRL0
585         ldr     r0, [r5, r2]
586         orr     r0, r0, #(1 << 29)
587         str     r0, [r5, r2]
588
589         ldr     r2, =MMDC1_MPDGCTRL0
590         ldr     r0, [r5, r2]
591         orr     r0, r0, #(0x1 << 29)
592         str     r0, [r5, r2]
593
594         /* MMDC0_MAPSR adopt power down enable. */
595         ldr     r0, [r5, #MMDC0_MAPSR]
596         bic     r0, r0, #0x01
597         str     r0, [r5, #MMDC0_MAPSR]
598
599         /* frc_msr + mu bypass */
600         ldr     r0, =0x00000060
601         str     r0, [r5, #MMDC0_MPMUR0]
602         ldr     r2, =MMDC1_MPMUR0
603         str     r0, [r5, r2]
604         ldr     r0, =0x00000460
605         str     r0, [r5, #MMDC0_MPMUR0]
606         ldr     r2, =MMDC1_MPMUR0
607         str     r0, [r5, r2]
608         ldr     r0, =0x00000c60
609         str     r0, [r5, #MMDC0_MPMUR0]
610         ldr     r2, =MMDC1_MPMUR0
611         str     r0, [r5, r2]
612
613 continue_dll_off_3:
614         /* clear SBS - unblock accesses to DDR. */
615         ldr     r0, [r5, #MMDC0_MADPCR0]
616         bic     r0, r0, #(0x1 << 8)
617         str     r0, [r5, #MMDC0_MADPCR0]
618
619         mov     r0, #0x0
620         str     r0, [r5, #MMDC0_MDSCR]
621 poll_conreq_clear_1:
622         ldr     r0, [r5, #MMDC0_MDSCR]
623         and     r0, r0, #(0x4 << 12)
624         cmp     r0, #(0x4 << 12)
625         beq     poll_conreq_clear_1
626
627         b       done
628
629 dll_on_mode:
630         /* assert DVFS - enter self refresh mode. */
631         ldr     r0, [r5, #MMDC0_MAPSR]
632         orr     r0, r0, #(1 << 21)
633         str     r0, [r5, #MMDC0_MAPSR]
634
635         /* de-assert CON_REQ. */
636         mov     r0, #0x0
637         str     r0, [r5, #MMDC0_MDSCR]
638
639         /* poll DVFS ack. */
640 poll_dvfs_set_2:
641         ldr     r0, [r5, #MMDC0_MAPSR]
642         and     r0, r0, #(1 << 25)
643         cmp     r0, #(1 << 25)
644         bne     poll_dvfs_set_2
645
646         ldr     r1, =528000000
647         cmp     r4, r1
648         beq     switch_freq_528
649
650         switch_to_400MHz
651
652         b       continue_dll_on
653
654 switch_freq_528:
655         switch_to_528MHz
656
657 continue_dll_on:
658
659         /* set SBS step-by-step mode. */
660         ldr     r0, [r5, #MMDC0_MADPCR0]
661         orr     r0, r0, #( 1 << 8)
662         str     r0, [r5, #MMDC0_MADPCR0]
663
664         /* clear DVFS - exit self refresh mode. */
665         ldr     r0, [r5, #MMDC0_MAPSR]
666         bic     r0, r0, #(1 << 21)
667         str     r0, [r5, #MMDC0_MAPSR]
668
669 poll_dvfs_clear_2:
670         ldr     r0, [r5, #MMDC0_MAPSR]
671         and     r0, r0, #(1 << 25)
672         cmp     r0, #(1 << 25)
673         beq     poll_dvfs_clear_2
674
675         /* if DLL is currently off, turn it back on. */
676         cmp     r9, #0
677         beq     update_calibration_only
678
679         ldr     r0, =0xa5390003
680         str     r0, [r5, #MMDC0_MPZQHWCTRL]
681         ldr     r2, =MMDC1_MPZQHWCTRL
682         str     r0, [r5, r2]
683
684         /* enable DQS gating. */
685         ldr     r2, =MMDC0_MPDGCTRL0
686         ldr     r0, [r5, r2]
687         bic     r0, r0, #(1 << 29)
688         str     r0, [r5, r2]
689
690         ldr     r2, =MMDC1_MPDGCTRL0
691         ldr     r0, [r5, r2]
692         bic     r0, r0, #(1 << 29)
693         str     r0, [r5, r2]
694
695         /* force measure. */
696         ldr     r0, =0x00000800
697         str     r0, [r5, #MMDC0_MPMUR0]
698         ldr     r2, =MMDC1_MPMUR0
699         str     r0, [r5, r2]
700
701         /* delay for while. */
702         ldr     r1, =4
703 delay5:
704         ldr     r2, =0
705 cont5:
706         ldr     r0, [r5, r2]
707         add     r2, r2, #4
708         cmp     r2, #16
709         bne     cont5
710         sub     r1, r1, #1
711         cmp     r1, #0
712         bgt     delay5
713
714         /* disable dqs pull down in the IOMUX. */
715         ldr     r1, [r11]
716         add     r11, r11, #8
717 update_iomux1:
718         ldr     r0, [r11, #0x0]
719         ldr     r3, [r11, #0x4]
720         str     r3, [r7, r0]
721         add     r11, r11, #8
722         sub     r1, r1, #1
723         cmp     r1, #0
724         bgt     update_iomux1
725
726         /* config MMDC timings to 528MHz. */
727         ldr     r9, [r8]
728         add     r8, r8, #8
729         ldr     r0, [r8, #0x0]
730         ldr     r3, [r8, #0x4]
731         str     r3, [r5, r0]
732         add     r8, r8, #8
733
734         ldr     r0, [r8, #0x0]
735         ldr     r3, [r8, #0x4]
736         str     r3, [r5, r0]
737         add     r8, r8, #8
738
739         /* update MISC register: WALAT, RALAT */
740         ldr     r0, =0x00081740
741         str     r0, [r5, #MMDC0_MDMISC]
742
743         /* configure ddr devices to dll on, odt. */
744         ldr     r0, =0x00028031
745         str     r0, [r5, #MMDC0_MDSCR]
746
747         ldr     r0, =0x00028039
748         str     r0, [r5, #MMDC0_MDSCR]
749
750         /* delay for while. */
751         ldr     r1, =4
752 delay7:
753         ldr     r2, =0
754 cont7:
755         ldr     r0, [r5, r2]
756         add     r2, r2, #4
757         cmp     r2, #16
758         bne     cont7
759         sub     r1, r1, #1
760         cmp     r1, #0
761         bgt     delay7
762
763         /* reset dll. */
764         ldr     r0, =0x09208030
765         str     r0, [r5, #MMDC0_MDSCR]
766
767         ldr     r0, =0x09208038
768         str     r0, [r5, #MMDC0_MDSCR]
769
770         /* delay for while. */
771         ldr     r1, =100
772 delay8:
773         ldr     r2, =0
774 cont8:
775         ldr     r0, [r5, r2]
776         add     r2, r2, #4
777         cmp     r2, #16
778         bne     cont8
779         sub     r1, r1, #1
780         cmp     r1, #0
781         bgt     delay8
782
783         ldr     r0, [r8, #0x0]
784         ldr     r3, [r8, #0x4]
785         str     r3, [r5, r0]
786         add     r8, r8, #8
787
788         ldr     r0, [r8, #0x0]
789         ldr     r3, [r8, #0x4]
790         str     r3, [r5, r0]
791         add     r8, r8, #8
792
793         ldr     r0, =0x00428031
794         str     r0, [r5, #MMDC0_MDSCR]
795
796         ldr     r0, =0x00428039
797         str     r0, [r5, #MMDC0_MDSCR]
798
799         ldr     r0, [r8, #0x0]
800         ldr     r3, [r8, #0x4]
801         str     r3, [r5, r0]
802         add     r8, r8, #8
803
804         ldr     r0, [r8, #0x0]
805         ldr     r3, [r8, #0x4]
806         str     r3, [r5, r0]
807         add     r8, r8, #8
808
809         /* issue a zq command. */
810         ldr     r0, =0x04008040
811         str     r0, [r5, #MMDC0_MDSCR]
812
813         ldr     r0, =0x04008048
814         str     r0, [r5, #MMDC0_MDSCR]
815
816         /* MMDC ODT enable. */
817         ldr     r0, [r8, #0x0]
818         ldr     r3, [r8, #0x4]
819         str     r3, [r5, r0]
820         add     r8, r8, #8
821
822         ldr     r2, =0x4818
823         str     r0, [r5, r2]
824
825         /* delay for while. */
826         ldr     r1, =40
827 delay15:
828         ldr     r2, =0
829 cont15:
830         ldr     r0, [r5, r2]
831         add     r2, r2, #4
832         cmp     r2, #16
833         bne     cont15
834         sub     r1, r1, #1
835         cmp     r1, #0
836         bgt     delay15
837
838         /* MMDC0_MAPSR adopt power down enable. */
839         ldr     r0, [r5, #MMDC0_MAPSR]
840         bic     r0, r0, #0x01
841         str     r0, [r5, #MMDC0_MAPSR]
842
843         /* enable MMDC power down timer. */
844         ldr     r0, [r5, #MMDC0_MDPDC]
845         orr     r0, r0, #(0x55 << 8)
846         str     r0, [r5, #MMDC0_MDPDC]
847
848         b       update_calibration
849
850 update_calibration_only:
851         ldr     r1, [r8]
852         sub     r1, r1, #7
853         add     r8, r8, #64
854         b       update_calib
855
856 update_calibration:
857         /* write the new calibration values. */
858         mov     r1, r9
859         sub     r1, r1, #7
860
861 update_calib:
862         ldr     r0, [r8, #0x0]
863         ldr     r3, [r8, #0x4]
864         str     r3, [r5, r0]
865         add     r8, r8, #8
866         sub     r1, r1, #1
867         cmp     r1, #0
868         bgt     update_calib
869
870         /* perform a force measurement. */
871         ldr     r0, =0x800
872         str     r0, [r5, #MMDC0_MPMUR0]
873         ldr     r2, =MMDC1_MPMUR0
874         str     r0, [r5, r2]
875
876         /* clear SBS - unblock DDR accesses. */
877         ldr     r0, [r5, #MMDC0_MADPCR0]
878         bic     r0, r0, #(1 << 8)
879         str     r0, [r5, #MMDC0_MADPCR0]
880
881         mov     r0, #0x0
882         str     r0, [r5, #MMDC0_MDSCR]
883 poll_conreq_clear_2:
884         ldr     r0, [r5, #MMDC0_MDSCR]
885         and     r0, r0, #(0x4 << 12)
886         cmp     r0, #(0x4 << 12)
887         beq     poll_conreq_clear_2
888
889 done:
890         /* Restore the TTBCR */
891         dsb
892         isb
893         /* Read TTBCR and set PD0=0, N = 0 */
894         mrc     p15, 0, r6, c2, c0, 2
895         bic     r6, r6, #0x11
896         mcr     p15, 0, r6, c2, c0, 2
897         dsb
898         isb
899
900         /* flush the TLB */
901         ldr     r6, =0x0
902         mcr     p15, 0, r6, c8, c3, 0
903         dsb
904         isb
905
906         /* restore registers */
907
908         ldmfd   sp!, {r4-r12}
909         mov     pc, lr
910
911         .type   mx6_do_ddr3_freq_change, #object
912 ENTRY(mx6_do_ddr_freq_change)
913         .word   mx6_ddr3_freq_change
914         .size   mx6_ddr3_freq_change, . - mx6_ddr3_freq_change