2 * Copyright (C) 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.
15 #include <linux/linkage.h>
17 #define PM_INFO_PBASE_OFFSET 0x0
18 #define PM_INFO_RESUME_ADDR_OFFSET 0x4
19 #define PM_INFO_PM_INFO_SIZE_OFFSET 0x8
20 #define PM_INFO_PM_INFO_TTBR_OFFSET 0xc
21 #define PM_INFO_MX6Q_MMDC_P_OFFSET 0x10
22 #define PM_INFO_MX6Q_MMDC_V_OFFSET 0x14
23 #define PM_INFO_MX6Q_IOMUXC_P_OFFSET 0x18
24 #define PM_INFO_MX6Q_IOMUXC_V_OFFSET 0x1c
25 #define PM_INFO_MX6Q_CCM_P_OFFSET 0x20
26 #define PM_INFO_MX6Q_CCM_V_OFFSET 0x24
27 #define PM_INFO_MX6Q_GPC_P_OFFSET 0x28
28 #define PM_INFO_MX6Q_GPC_V_OFFSET 0x2c
29 #define PM_INFO_MX6Q_L2_P_OFFSET 0x30
30 #define PM_INFO_MX6Q_L2_V_OFFSET 0x34
31 #define PM_INFO_MX6Q_ANATOP_P_OFFSET 0x38
32 #define PM_INFO_MX6Q_ANATOP_V_OFFSET 0x3c
33 #define PM_INFO_MX6Q_SRC_P_OFFSET 0x40
34 #define PM_INFO_MX6Q_SRC_V_OFFSET 0x44
35 #define PM_INFO_MX6Q_SEMA4_P_OFFSET 0x48
36 #define PM_INFO_MX6Q_SEMA4_V_OFFSET 0x4c
37 #define PM_INFO_MX6Q_SAVED_DIAGNOSTIC_OFFSET 0x50
38 #define PM_INFO_MMDC_IO_NUM_OFFSET 0x54
39 #define PM_INFO_MMDC_IO_VAL_OFFSET 0x58
41 #define MX6Q_MMDC_MAPSR 0x404
42 #define MX6Q_MMDC_MPDGCTRL0 0x83c
43 #define MX6Q_SRC_GPR1 0x20
44 #define MX6Q_SRC_GPR2 0x24
45 #define MX6Q_GPC_IMR1 0x08
46 #define MX6Q_GPC_IMR2 0x0c
47 #define MX6Q_GPC_IMR3 0x10
48 #define MX6Q_GPC_IMR4 0x14
49 #define MX6Q_CCM_CCR 0x0
51 .globl mx6sx_lpm_wfi_start
52 .globl mx6sx_lpm_wfi_end
54 .macro pll_do_wait_lock
72 ldr r10, [r0, #PM_INFO_MX6Q_CCM_V_OFFSET]
79 /* set perclk to 6MHz */
85 /* set mmdc to 1MHz, periph2_clk2 need to be @8MHz */
88 orr r7, r7, #(0x7 << 3)
93 ldr r10, [r0, #PM_INFO_MX6Q_ANATOP_V_OFFSET]
95 /* enable PLL1 bypass output */
100 ldr r10, [r0, #PM_INFO_MX6Q_CCM_V_OFFSET]
102 /* set pll1_sw to from pll1 main */
107 /* set step from osc */
112 /* set pll1_sw to from step */
117 ldr r10, [r0, #PM_INFO_MX6Q_ANATOP_V_OFFSET]
119 /* Disable PLL1 bypass output */
125 * disable pll2, suppose when system enter low
126 * power idle mode, only 396MHz pfd needs pll2,
127 * now we switch arm clock to OSC, we can disable
128 * pll2 now, gate pll2_pfd2 first.
130 ldr r7, [r10, #0x100]
132 str r7, [r10, #0x100]
144 ldreq r10, [r0, #PM_INFO_MX6Q_ANATOP_V_OFFSET]
145 ldrne r10, [r0, #PM_INFO_MX6Q_ANATOP_P_OFFSET]
147 /* enable pll2 and pll2_pfd2 */
156 ldr r7, [r10, #0x100]
158 str r7, [r10, #0x100]
160 /* enable PLL1 bypass output */
166 ldreq r10, [r0, #PM_INFO_MX6Q_CCM_V_OFFSET]
167 ldrne r10, [r0, #PM_INFO_MX6Q_CCM_P_OFFSET]
169 /* set perclk back to 24MHz */
174 /* set mmdc back to 24MHz */
177 bic r7, r7, #(0x7 << 3)
180 /* set ahb div back to 24MHz */
187 /* set pll1_sw to from pll1 main */
192 /* set step from pll2_pfd2 */
197 /* set pll1_sw to from step */
203 ldreq r10, [r0, #PM_INFO_MX6Q_ANATOP_V_OFFSET]
204 ldrne r10, [r0, #PM_INFO_MX6Q_ANATOP_P_OFFSET]
206 /* disable PLL1 bypass output */
213 .macro anatop_enter_idle
215 ldr r10, [r0, #PM_INFO_MX6Q_ANATOP_V_OFFSET]
218 * check whether any PLL is enabled, as only when
219 * there is no PLLs enabled, 2P5 and 1P1 can be
220 * off and only enable weak ones.
225 ands r7, r7, #(1 << 31)
230 ands r7, r7, #(1 << 31)
235 ands r7, r7, #(1 << 31)
240 ands r7, r7, #(1 << 31)
245 ands r7, r7, #(1 << 31)
250 ands r7, r7, #(1 << 31)
255 ands r7, r7, #(1 << 31)
258 /* enable weak 2P5 and turn off regular 2P5 */
259 ldr r7, [r10, #0x130]
261 str r7, [r10, #0x130]
263 str r7, [r10, #0x130]
265 /* enable weak 1p1 and turn off regular 1P1 */
266 ldr r7, [r10, #0x110]
268 str r7, [r10, #0x110]
270 str r7, [r10, #0x110]
272 /* check whether ARM LDO is bypassed */
273 ldr r7, [r10, #0x140]
278 /* low power band gap enable */
279 ldr r7, [r10, #0x270]
281 str r7, [r10, #0x270]
283 /* turn off the bias current from the regular bandgap */
284 ldr r7, [r10, #0x270]
286 str r7, [r10, #0x270]
289 * clear the REFTOP_SELFBIASOFF,
290 * self-bias circuit of the band gap.
291 * Per RM, should be cleared when
292 * band gap is powered down.
294 ldr r7, [r10, #0x150]
296 str r7, [r10, #0x150]
298 /* turn off regular bandgap */
299 ldr r7, [r10, #0x150]
301 str r7, [r10, #0x150]
303 /* only switch to RC-OSC clk after TO1.2 */
304 ldr r7, [r10, #0x260]
309 /* switch to RC-OSC */
310 ldr r7, [r10, #0x270]
312 str r7, [r10, #0x270]
314 /* turn off XTAL-OSC */
315 ldr r7, [r10, #0x150]
316 orr r7, r7, #0x40000000
317 str r7, [r10, #0x150]
319 /* lower OSC current by 37.5% */
320 ldr r7, [r10, #0x150]
322 str r7, [r10, #0x150]
326 .macro anatop_exit_idle
329 ldreq r10, [r0, #PM_INFO_MX6Q_ANATOP_V_OFFSET]
330 ldrne r10, [r0, #PM_INFO_MX6Q_ANATOP_P_OFFSET]
332 /* increase OSC current to normal */
333 ldr r7, [r10, #0x150]
335 str r7, [r10, #0x150]
337 /* only switch to RC-OSC after TO1.2 */
338 ldr r7, [r10, #0x260]
343 /* turn on XTAL-OSC and detector */
344 ldr r7, [r10, #0x150]
345 bic r7, r7, #0x40000000
347 str r7, [r10, #0x150]
349 /* wait for XTAL stable */
351 ldr r7, [r10, #0x150]
355 /* switch to XTAL-OSC */
356 ldr r7, [r10, #0x270]
358 str r7, [r10, #0x270]
360 /* turn off XTAL-OSC detector */
361 ldr r7, [r10, #0x150]
363 str r7, [r10, #0x150]
365 /* check whether we need to enable 2P5/1P1 */
366 ldr r7, [r10, #0x110]
367 ands r7, r7, #0x40000
370 /* check whether ARM LDO is bypassed */
371 ldr r7, [r10, #0x140]
376 /* turn on regular bandgap and wait for stable */
377 ldr r7, [r10, #0x150]
379 str r7, [r10, #0x150]
381 ldr r7, [r10, #0x150]
386 * set the REFTOP_SELFBIASOFF,
387 * self-bias circuit of the band gap.
389 ldr r7, [r10, #0x150]
391 str r7, [r10, #0x150]
393 /* turn on the bias current from the regular bandgap */
394 ldr r7, [r10, #0x270]
396 str r7, [r10, #0x270]
398 /* low power band gap disable */
399 ldr r7, [r10, #0x270]
401 str r7, [r10, #0x270]
403 /* enable regular 2P5 and turn off weak 2P5 */
404 ldr r7, [r10, #0x130]
406 str r7, [r10, #0x130]
408 /* Ensure the 2P5 is up. */
410 ldr r7, [r10, #0x130]
411 ands r7, r7, #0x20000
413 ldr r7, [r10, #0x130]
415 str r7, [r10, #0x130]
417 /* enable regular 1p1 and turn off weak 1P1 */
418 ldr r7, [r10, #0x110]
420 str r7, [r10, #0x110]
422 ldr r7, [r10, #0x110]
423 ands r7, r7, #0x20000
425 ldr r7, [r10, #0x110]
427 str r7, [r10, #0x110]
431 .macro disable_l1_dcache
434 * Flush all data from the L1 data cache before disabling
438 ldr r7, =v7_flush_dcache_all
443 /* disable d-cache */
444 mrc p15, 0, r7, c1, c0, 0
445 bic r7, r7, #(1 << 2)
446 mcr p15, 0, r7, c1, c0, 0
451 ldr r7, =v7_flush_dcache_all
458 .macro mmdc_enter_dvfs_mode
460 /* disable automatic power savings. */
461 ldr r7, [r10, #MX6Q_MMDC_MAPSR]
463 str r7, [r10, #MX6Q_MMDC_MAPSR]
465 /* disable power down timer */
470 /* make the DDR explicitly enter self-refresh. */
471 ldr r7, [r10, #MX6Q_MMDC_MAPSR]
472 orr r7, r7, #(1 << 21)
473 str r7, [r10, #MX6Q_MMDC_MAPSR]
475 ldr r7, [r10, #MX6Q_MMDC_MAPSR]
476 ands r7, r7, #(1 << 25)
483 /* restore MMDC IO */
485 ldreq r10, [r0, #PM_INFO_MX6Q_IOMUXC_V_OFFSET]
486 ldrne r10, [r0, #PM_INFO_MX6Q_IOMUXC_P_OFFSET]
488 ldr r6, [r0, #PM_INFO_MMDC_IO_NUM_OFFSET]
489 ldr r7, =PM_INFO_MMDC_IO_VAL_OFFSET
499 ldreq r10, [r0, #PM_INFO_MX6Q_MMDC_V_OFFSET]
500 ldrne r10, [r0, #PM_INFO_MX6Q_MMDC_P_OFFSET]
502 /* reset read FIFO, RST_RD_FIFO */
503 ldr r7, =MX6Q_MMDC_MPDGCTRL0
505 orr r6, r6, #(1 << 31)
509 ands r6, r6, #(1 << 31)
512 /* reset FIFO a second time */
514 orr r6, r6, #(1 << 31)
518 ands r6, r6, #(1 << 31)
521 /* let DDR out of self-refresh */
522 ldr r7, [r10, #MX6Q_MMDC_MAPSR]
523 bic r7, r7, #(1 << 21)
524 str r7, [r10, #MX6Q_MMDC_MAPSR]
526 ldr r7, [r10, #MX6Q_MMDC_MAPSR]
527 ands r7, r7, #(1 << 25)
530 /* enable power down timer */
535 /* enable DDR auto power saving */
536 ldr r7, [r10, #MX6Q_MMDC_MAPSR]
538 str r7, [r10, #MX6Q_MMDC_MAPSR]
544 /* lock share memory sema4 */
546 ldreq r10, [r0, #PM_INFO_MX6Q_SEMA4_V_OFFSET]
547 ldrne r10, [r0, #PM_INFO_MX6Q_SEMA4_P_OFFSET]
559 /* unlock share memory sema4 */
561 ldreq r10, [r0, #PM_INFO_MX6Q_SEMA4_V_OFFSET]
562 ldrne r10, [r0, #PM_INFO_MX6Q_SEMA4_P_OFFSET]
568 .macro tlb_set_to_ocram
571 mrc p15, 0, r7, c2, c0, 1
572 str r7, [r0, #PM_INFO_PM_INFO_TTBR_OFFSET]
575 * To ensure no page table walks occur in DDR, we
576 * have a another page table stored in IRAM that only
577 * contains entries pointing to IRAM, AIPS1 and AIPS2.
578 * We need to set the TTBR1 to the new IRAM TLB.
579 * Do the following steps:
580 * 1. Flush the Branch Target Address Cache (BTAC)
581 * 2. Set TTBR1 to point to IRAM page table.
582 * 3. Disable page table walks in TTBR0 (PD0 = 1)
583 * 4. Set TTBR0.N=1, implying 0-2G is translated by TTBR0
584 * and 2-4G is translated by TTBR1.
587 ldr r6, =iram_tlb_phys_addr
590 /* Flush the BTAC. */
592 mcr p15, 0, r6, c7, c1, 6
594 /* Disable Branch Prediction, Z bit in SCTLR. */
595 mrc p15, 0, r6, c1, c0, 0
597 mcr p15, 0, r6, c1, c0, 0
602 /* Store the IRAM table in TTBR1 */
603 mcr p15, 0, r7, c2, c0, 1
605 /* Read TTBCR and set PD0=1, N = 1 */
606 mrc p15, 0, r6, c2, c0, 2
608 mcr p15, 0, r6, c2, c0, 2
615 mcr p15, 0, r6, c8, c3, 0
619 .macro tlb_back_to_ddr
621 /* Restore the TTBCR */
626 /* Read TTBCR and set PD0=0, N = 0 */
627 mrc p15, 0, r6, c2, c0, 2
629 mcr p15, 0, r6, c2, c0, 2
636 mcr p15, 0, r6, c8, c3, 0
641 /* Enable Branch Prediction, Z bit in SCTLR. */
642 mrc p15, 0, r6, c1, c0, 0
644 mcr p15, 0, r6, c1, c0, 0
646 /* Flush the Branch Target Address Cache (BTAC) */
648 mcr p15, 0, r6, c7, c1, 6
651 ldr r7, [r0, #PM_INFO_PM_INFO_TTBR_OFFSET]
652 mcr p15, 0, r7, c2, c0, 1
656 .extern iram_tlb_phys_addr
658 /* imx6sx_low_power_idle */
661 ENTRY(imx6sx_low_power_idle)
665 /* get necessary info from pm_info */
666 ldr r1, [r0, #PM_INFO_PBASE_OFFSET]
667 ldr r2, [r0, #PM_INFO_PM_INFO_SIZE_OFFSET]
670 * counting the resume address in iram
671 * to set it in SRC register.
673 ldr r5, =imx6sx_low_power_idle
679 /* store physical resume addr and pm_info address. */
680 ldr r10, [r0, #PM_INFO_MX6Q_SRC_V_OFFSET]
684 /* save disagnostic register */
685 mrc p15, 0, r7, c15, c0, 1
686 str r7, [r0, #PM_INFO_MX6Q_SAVED_DIAGNOSTIC_OFFSET]
688 /* set ARM power to be gated */
689 ldr r10, [r0, #PM_INFO_MX6Q_GPC_V_OFFSET]
691 str r7, [r10, #0x2a0]
695 #ifdef CONFIG_CACHE_L2X0
697 ldr r10, [r0, #PM_INFO_MX6Q_L2_V_OFFSET]
699 /* Wait for background operations to complete. */
701 ldr r7, [r10, #0x730]
703 bne wait_for_l2_to_idle
706 str r7, [r10, #0x730]
708 str r7, [r10, #0x100]
716 /* make sure MMDC in self-refresh */
717 ldr r10, [r0, #PM_INFO_MX6Q_MMDC_V_OFFSET]
720 /* save DDR IO settings */
721 ldr r10, [r0, #PM_INFO_MX6Q_IOMUXC_V_OFFSET]
723 ldr r7, [r0, #PM_INFO_MMDC_IO_NUM_OFFSET]
724 ldr r8, =PM_INFO_MMDC_IO_VAL_OFFSET
726 save_and_set_mmdc_io_lpm:
732 bne save_and_set_mmdc_io_lpm
741 * mask all GPC interrupts before
742 * enabling the RBC counters to
743 * avoid the counter starting too
744 * early if an interupt is already
747 ldr r10, [r0, #PM_INFO_MX6Q_GPC_V_OFFSET]
748 ldr r4, [r10, #MX6Q_GPC_IMR1]
749 ldr r5, [r10, #MX6Q_GPC_IMR2]
750 ldr r6, [r10, #MX6Q_GPC_IMR3]
751 ldr r7, [r10, #MX6Q_GPC_IMR4]
754 str r3, [r10, #MX6Q_GPC_IMR1]
755 str r3, [r10, #MX6Q_GPC_IMR2]
756 str r3, [r10, #MX6Q_GPC_IMR3]
757 str r3, [r10, #MX6Q_GPC_IMR4]
760 * enable the RBC bypass counter here
761 * to hold off the interrupts. RBC counter
762 * = 1 (30us). With this setting, the latency
763 * from wakeup interrupt to ARM power up
766 ldr r10, [r0, #PM_INFO_MX6Q_CCM_V_OFFSET]
767 ldr r3, [r10, #MX6Q_CCM_CCR]
768 bic r3, r3, #(0x3f << 21)
769 orr r3, r3, #(0x1 << 21)
770 str r3, [r10, #MX6Q_CCM_CCR]
772 /* enable the counter. */
773 ldr r3, [r10, #MX6Q_CCM_CCR]
774 orr r3, r3, #(0x1 << 27)
775 str r3, [r10, #MX6Q_CCM_CCR]
777 /* unmask all the GPC interrupts. */
778 ldr r10, [r0, #PM_INFO_MX6Q_GPC_V_OFFSET]
779 str r4, [r10, #MX6Q_GPC_IMR1]
780 str r5, [r10, #MX6Q_GPC_IMR2]
781 str r6, [r10, #MX6Q_GPC_IMR3]
782 str r7, [r10, #MX6Q_GPC_IMR4]
785 * now delay for a short while (3usec)
786 * ARM is at 1GHz at this point
787 * so a short loop should be enough.
788 * this delay is required to ensure that
789 * the RBC counter can start counting in
790 * case an interrupt is already pending
791 * or in case an interrupt arrives just
792 * as ARM is about to assert DSM_request.
838 /* clear ARM power gate setting */
839 ldr r10, [r0, #PM_INFO_MX6Q_GPC_V_OFFSET]
841 str r7, [r10, #0x2a0]
844 mrc p15, 0, r7, c1, c0, 0
845 orr r7, r7, #(1 << 2)
846 mcr p15, 0, r7, c1, c0, 0
848 #ifdef CONFIG_CACHE_L2X0
849 ldr r10, [r0, #PM_INFO_MX6Q_L2_V_OFFSET]
852 str r7, [r10, #0x100]
857 /* Restore registers */
863 /* invalidate L1 I-cache first */
865 mcr p15, 0, r1, c7, c5, 0
866 mcr p15, 0, r1, c7, c5, 0
867 mcr p15, 0, r1, c7, c5, 6
868 /* enable the Icache and branch prediction */
870 mcr p15, 0, r1, c1, c0, 0
872 /* restore disagnostic register */
873 ldr r7, [r0, #PM_INFO_MX6Q_SAVED_DIAGNOSTIC_OFFSET]
874 mcr p15, 0, r7, c15, c0, 1
876 /* get physical resume address from pm_info. */
877 ldr lr, [r0, #PM_INFO_RESUME_ADDR_OFFSET]
878 /* clear core0's entry and parameter */
879 ldr r10, [r0, #PM_INFO_MX6Q_SRC_P_OFFSET]
881 str r7, [r10, #MX6Q_SRC_GPR1]
882 str r7, [r10, #MX6Q_SRC_GPR2]
884 /* clear ARM power gate setting */
885 ldr r10, [r0, #PM_INFO_MX6Q_GPC_P_OFFSET]
887 str r7, [r10, #0x2a0]
896 /* Restore registers */