2 * Copyright (C) 2011-2014 Freescale Semiconductor, Inc. All Rights Reserved.
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.
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.
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.
19 #include <linux/linkage.h>
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
38 #define CCM_CBCDR 0x14
39 #define CCM_CBCMR 0x18
40 #define CCM_CSCMR1 0x1c
41 #define CCM_CDHIPR 0x48
43 #define L2_CACHE_SYNC 0x730
45 .extern iram_tlb_phys_addr
49 .macro switch_to_528MHz
51 /* check if periph_clk_sel is already set */
52 ldr r0, [r6, #CCM_CBCDR]
53 and r0, r0, #(1 << 25)
55 beq set_ahb_podf_before_switch
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]
62 ldr r0, [r6, #CCM_CBCDR]
63 bic r0, r0, #(0x38 << 20)
64 str r0, [r6, #CCM_CBCDR]
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,
71 ldr r0, [r6, #CCM_CBCDR]
75 orr r0, r0, #(1 << 16)
76 str r0, [r6, #CCM_CBCDR]
79 ldr r0, [r6, #CCM_CDHIPR]
81 bne wait_div_update528
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]
89 ldr r0, [r6, #CCM_CDHIPR]
91 bne periph_clk_switch3
93 b switch_pre_periph_clk_528
95 set_ahb_podf_before_switch:
97 * set the MMDC_DIV=1, AXI_DIV = 2, AHB_DIV=4,
99 ldr r0, [r6, #CCM_CBCDR]
103 orr r0, r0, #(1 << 16)
104 str r0, [r6, #CCM_CBCDR]
106 wait_div_update528_1:
107 ldr r0, [r6, #CCM_CDHIPR]
109 bne wait_div_update528_1
111 switch_pre_periph_clk_528:
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]
118 /* now switch periph_clk back. */
119 ldr r0, [r6, #CCM_CBCDR]
120 bic r0, r0, #(1 << 25)
121 str r0, [r6, #CCM_CBCDR]
124 ldr r0, [r6, #CCM_CDHIPR]
126 bne periph_clk_switch4
130 .macro switch_to_400MHz
132 /* check if periph_clk_sel is already set. */
133 ldr r0, [r6, #CCM_CBCDR]
134 and r0, r0, #(1 << 25)
136 beq set_ahb_podf_before_switch1
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]
143 ldr r0, [r6, #CCM_CBCDR]
144 bic r0, r0, #(0x38 << 24)
145 str r0, [r6, #CCM_CBCDR]
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]
153 ldr r0, [r6, #CCM_CDHIPR]
155 bne periph_clk_switch5
157 b switch_pre_periph_clk_400
159 set_ahb_podf_before_switch1:
161 * set the MMDC_DIV=1, AXI_DIV = 2, AHB_DIV=4,
163 ldr r0, [r6, #CCM_CBCDR]
166 orr r0, r0, #(0x9 << 8)
167 orr r0, r0, #(1 << 16)
168 str r0, [r6, #CCM_CBCDR]
170 wait_div_update400_1:
171 ldr r0, [r6, #CCM_CDHIPR]
173 bne wait_div_update400_1
175 switch_pre_periph_clk_400:
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]
183 /* now switch periph_clk back. */
184 ldr r0, [r6, #CCM_CBCDR]
185 bic r0, r0, #(1 << 25)
186 str r0, [r6, #CCM_CBCDR]
189 ldr r0, [r6, #CCM_CDHIPR]
191 bne periph_clk_switch6
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,
198 ldr r0, [r6, #CCM_CBCDR]
201 orr r0, r0, #(0x9 << 8)
202 orr r0, r0, #(1 << 16)
203 str r0, [r6, #CCM_CBCDR]
205 wait_div_update400_2:
206 ldr r0, [r6, #CCM_CDHIPR]
208 bne wait_div_update400_2
212 .macro switch_to_50MHz
214 /* check if periph_clk_sel is already set. */
215 ldr r0, [r6, #CCM_CBCDR]
216 and r0, r0, #(1 << 25)
218 beq switch_pre_periph_clk_50
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.
225 ldr r0, [r6, #CCM_CBCMR]
226 bic r0, r0, #(0x3 << 12)
227 str r0, [r6, #CCM_CBCMR]
229 ldr r0, [r6, #CCM_CBCDR]
230 bic r0, r0, #(0x38 << 24)
231 str r0, [r6, #CCM_CBCDR]
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]
238 periph_clk_switch_50:
239 ldr r0, [r6, #CCM_CDHIPR]
241 bne periph_clk_switch_50
243 switch_pre_periph_clk_50:
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]
251 * set the MMDC_DIV=4, AXI_DIV = 4, AHB_DIV=8,
253 ldr r0, [r6, #CCM_CBCDR]
256 orr r0, r0, #(0x18 << 16)
257 orr r0, r0, #(0x3 << 16)
260 * if changing AHB divider remember to change
261 * the IPGPER divider too below.
264 str r0, [r6, #CCM_CBCDR]
267 ldr r0, [r6, #CCM_CDHIPR]
269 bne wait_div_update_50
271 /* now switch periph_clk back. */
272 ldr r0, [r6, #CCM_CBCDR]
273 bic r0, r0, #(1 << 25)
274 str r0, [r6, #CCM_CBCDR]
277 ldr r0, [r6, #CCM_CDHIPR]
279 bne periph_clk_switch2
283 .macro switch_to_24MHz
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
291 ldr r0, [r6, #CCM_CBCMR]
292 bic r0, r0, #(0x3 << 12)
293 orr r0, r0, #(1 << 12)
294 str r0, [r6, #CCM_CBCMR]
296 ldr r0, [r6, #CCM_CBCDR]
297 bic r0, r0, #(0x38 << 24)
298 str r0, [r6, #CCM_CBCDR]
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]
306 ldr r0, [r6, #CCM_CDHIPR]
308 bne periph_clk_switch1
310 /* change all the dividers to 1. */
311 ldr r0, [r6, #CCM_CBCDR]
314 orr r0, r0, #(1 << 8)
315 str r0, [r6, #CCM_CBCDR]
317 /* Wait for the divider to change. */
319 ldr r0, [r6, #CCM_CDHIPR]
326 * mx6_ddr3_freq_change
328 * idle the processor (eg, wait for interrupt).
329 * make sure DDR is in self-refresh.
330 * IRQs are already disabled.
332 ENTRY(mx6_ddr3_freq_change)
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.
361 /* Flush the Branch Target Address Cache (BTAC) */
363 mcr p15, 0, r6, c7, c1, 6
364 ldr r6, =iram_tlb_phys_addr
368 /* Store the IRAM table in TTBR1 */
369 mcr p15, 0, r6, c2, c0, 1
371 /* Read TTBCR and set PD0=1, N = 1 */
372 mrc p15, 0, r6, c2, c0, 2
374 mcr p15, 0, r6, c2, c0, 2
381 mcr p15, 0, r6, c8, c3, 0
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)
390 #ifdef CONFIG_CACHE_L2X0
392 * Make sure the L2 buffers are drained.
393 * Sync operation on L2 drains the buffers.
396 str r1, [r12, #L2_CACHE_SYNC]
399 /* disable automatic power saving. */
400 ldr r0, [r5, #MMDC0_MAPSR]
402 str r0, [r5, #MMDC0_MAPSR]
404 /* disable MMDC power down timer. */
405 ldr r0, [r5, #MMDC0_MDPDC]
406 bic r0, r0, #(0xff << 8)
407 str r0, [r5, #MMDC0_MDPDC]
409 /* delay for a while */
424 str r0, [r5, #MMDC0_MDSCR]
426 ldr r0, [r5, #MMDC0_MDSCR]
427 and r0, r0, #(0x4 << 12)
429 bne poll_conreq_set_1
432 str r0, [r5, #MMDC0_MDSCR]
434 str r0, [r5, #MMDC0_MDSCR]
437 * if requested frequency is greater than
438 * 300MHz go to DLL on mode.
446 /* if DLL is currently on, turn it off. */
448 beq continue_dll_off_1
451 str r0, [r5, #MMDC0_MDSCR]
454 str r0, [r5, #MMDC0_MDSCR]
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]
474 /* de-assert con_req */
476 str r0, [r5, #MMDC0_MDSCR]
479 ldr r0, [r5, #MMDC0_MAPSR]
480 and r0, r0, #(1 << 25)
496 /* set SBS - block ddr accesses */
497 ldr r0, [r5, #MMDC0_MADPCR0]
498 orr r0, r0, #(1 << 8)
499 str r0, [r5, #MMDC0_MADPCR0]
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]
507 ldr r0, [r5, #MMDC0_MAPSR]
508 and r0, r0, #(1 << 25)
510 beq poll_dvfs_clear_1
512 /* if DLL was previously on, continue DLL off routine. */
514 beq continue_dll_off_3
517 str r0, [r5, #MMDC0_MDSCR]
520 str r0, [r5, #MMDC0_MDSCR]
523 str r0, [r5, #MMDC0_MDSCR]
526 str r0, [r5, #MMDC0_MDSCR]
529 str r0, [r5, #MMDC0_MDSCR]
532 str r0, [r5, #MMDC0_MDSCR]
534 /* delay for a while. */
547 ldr r0, [r5, #MMDC0_MDCF0]
550 str r0, [r5, #MMDC0_MDCF0]
552 ldr r0, [r5, #MMDC0_MDCF1]
555 str r0, [r5, #MMDC0_MDCF1]
558 str r0, [r5, #MMDC0_MDMISC]
560 /* enable dqs pull down in the IOMUX. */
568 orr r3, r3, #(0x3 << 12)
578 ldr r2, =MMDC0_MPODTCTRL
580 ldr r2, =MMDC1_MPODTCTRL
583 /* DQS gating disabled. */
584 ldr r2, =MMDC0_MPDGCTRL0
586 orr r0, r0, #(1 << 29)
589 ldr r2, =MMDC1_MPDGCTRL0
591 orr r0, r0, #(0x1 << 29)
594 /* MMDC0_MAPSR adopt power down enable. */
595 ldr r0, [r5, #MMDC0_MAPSR]
597 str r0, [r5, #MMDC0_MAPSR]
599 /* frc_msr + mu bypass */
601 str r0, [r5, #MMDC0_MPMUR0]
602 ldr r2, =MMDC1_MPMUR0
605 str r0, [r5, #MMDC0_MPMUR0]
606 ldr r2, =MMDC1_MPMUR0
609 str r0, [r5, #MMDC0_MPMUR0]
610 ldr r2, =MMDC1_MPMUR0
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]
620 str r0, [r5, #MMDC0_MDSCR]
622 ldr r0, [r5, #MMDC0_MDSCR]
623 and r0, r0, #(0x4 << 12)
625 beq poll_conreq_clear_1
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]
635 /* de-assert CON_REQ. */
637 str r0, [r5, #MMDC0_MDSCR]
641 ldr r0, [r5, #MMDC0_MAPSR]
642 and r0, r0, #(1 << 25)
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]
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]
670 ldr r0, [r5, #MMDC0_MAPSR]
671 and r0, r0, #(1 << 25)
673 beq poll_dvfs_clear_2
675 /* if DLL is currently off, turn it back on. */
677 beq update_calibration_only
680 str r0, [r5, #MMDC0_MPZQHWCTRL]
681 ldr r2, =MMDC1_MPZQHWCTRL
684 /* enable DQS gating. */
685 ldr r2, =MMDC0_MPDGCTRL0
687 bic r0, r0, #(1 << 29)
690 ldr r2, =MMDC1_MPDGCTRL0
692 bic r0, r0, #(1 << 29)
697 str r0, [r5, #MMDC0_MPMUR0]
698 ldr r2, =MMDC1_MPMUR0
701 /* delay for while. */
714 /* disable dqs pull down in the IOMUX. */
726 /* config MMDC timings to 528MHz. */
739 /* update MISC register: WALAT, RALAT */
741 str r0, [r5, #MMDC0_MDMISC]
743 /* configure ddr devices to dll on, odt. */
745 str r0, [r5, #MMDC0_MDSCR]
748 str r0, [r5, #MMDC0_MDSCR]
750 /* delay for while. */
765 str r0, [r5, #MMDC0_MDSCR]
768 str r0, [r5, #MMDC0_MDSCR]
770 /* delay for while. */
794 str r0, [r5, #MMDC0_MDSCR]
797 str r0, [r5, #MMDC0_MDSCR]
809 /* issue a zq command. */
811 str r0, [r5, #MMDC0_MDSCR]
814 str r0, [r5, #MMDC0_MDSCR]
816 /* MMDC ODT enable. */
825 /* delay for while. */
838 /* MMDC0_MAPSR adopt power down enable. */
839 ldr r0, [r5, #MMDC0_MAPSR]
841 str r0, [r5, #MMDC0_MAPSR]
843 /* enable MMDC power down timer. */
844 ldr r0, [r5, #MMDC0_MDPDC]
845 orr r0, r0, #(0x55 << 8)
846 str r0, [r5, #MMDC0_MDPDC]
850 update_calibration_only:
857 /* write the new calibration values. */
870 /* perform a force measurement. */
872 str r0, [r5, #MMDC0_MPMUR0]
873 ldr r2, =MMDC1_MPMUR0
876 /* clear SBS - unblock DDR accesses. */
877 ldr r0, [r5, #MMDC0_MADPCR0]
878 bic r0, r0, #(1 << 8)
879 str r0, [r5, #MMDC0_MADPCR0]
882 str r0, [r5, #MMDC0_MDSCR]
884 ldr r0, [r5, #MMDC0_MDSCR]
885 and r0, r0, #(0x4 << 12)
887 beq poll_conreq_clear_2
890 /* Restore the TTBCR */
893 /* Read TTBCR and set PD0=0, N = 0 */
894 mrc p15, 0, r6, c2, c0, 2
896 mcr p15, 0, r6, c2, c0, 2
902 mcr p15, 0, r6, c8, c3, 0
906 /* restore registers */
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