Merge tag 'mips_5.15' of git://git.kernel.org/pub/scm/linux/kernel/git/mips/linux
[linux-2.6-microblaze.git] / arch / arm / mach-at91 / pm_suspend.S
index b683c2c..cbd61a3 100644 (file)
@@ -22,39 +22,57 @@ tmp3        .req    r6
 
 /*
  * Wait until master clock is ready (after switching master clock source)
+ *
+ * @r_mckid:   register holding master clock identifier
+ *
+ * Side effects: overwrites r7, r8
  */
-       .macro wait_mckrdy
-1:     ldr     tmp1, [pmc, #AT91_PMC_SR]
-       tst     tmp1, #AT91_PMC_MCKRDY
-       beq     1b
+       .macro wait_mckrdy r_mckid
+#ifdef CONFIG_SOC_SAMA7
+       cmp     \r_mckid, #0
+       beq     1f
+       mov     r7, #AT91_PMC_MCKXRDY
+       b       2f
+#endif
+1:     mov     r7, #AT91_PMC_MCKRDY
+2:     ldr     r8, [pmc, #AT91_PMC_SR]
+       and     r8, r7
+       cmp     r8, r7
+       bne     2b
        .endm
 
 /*
  * Wait until master oscillator has stabilized.
+ *
+ * Side effects: overwrites r7
  */
        .macro wait_moscrdy
-1:     ldr     tmp1, [pmc, #AT91_PMC_SR]
-       tst     tmp1, #AT91_PMC_MOSCS
+1:     ldr     r7, [pmc, #AT91_PMC_SR]
+       tst     r7, #AT91_PMC_MOSCS
        beq     1b
        .endm
 
 /*
  * Wait for main oscillator selection is done
+ *
+ * Side effects: overwrites r7
  */
        .macro wait_moscsels
-1:     ldr     tmp1, [pmc, #AT91_PMC_SR]
-       tst     tmp1, #AT91_PMC_MOSCSELS
+1:     ldr     r7, [pmc, #AT91_PMC_SR]
+       tst     r7, #AT91_PMC_MOSCSELS
        beq     1b
        .endm
 
 /*
  * Put the processor to enter the idle state
+ *
+ * Side effects: overwrites r7
  */
        .macro at91_cpu_idle
 
 #if defined(CONFIG_CPU_V7)
-       mov     tmp1, #AT91_PMC_PCK
-       str     tmp1, [pmc, #AT91_PMC_SCDR]
+       mov     r7, #AT91_PMC_PCK
+       str     r7, [pmc, #AT91_PMC_SCDR]
 
        dsb
 
@@ -65,102 +83,375 @@ tmp3      .req    r6
 
        .endm
 
+/**
+ * Set state for 2.5V low power regulator
+ * @ena: 0 - disable regulator
+ *      1 - enable regulator
+ *
+ * Side effects: overwrites r7, r8, r9, r10
+ */
+       .macro at91_2_5V_reg_set_low_power ena
+#ifdef CONFIG_SOC_SAMA7
+       ldr     r7, .sfrbu
+       mov     r8, #\ena
+       ldr     r9, [r7, #AT91_SFRBU_25LDOCR]
+       orr     r9, r9, #AT91_SFRBU_25LDOCR_LP
+       cmp     r8, #1
+       beq     lp_done_\ena
+       bic     r9, r9, #AT91_SFRBU_25LDOCR_LP
+lp_done_\ena:
+       ldr     r10, =AT91_SFRBU_25LDOCR_LDOANAKEY
+       orr     r9, r9, r10
+       str     r9, [r7, #AT91_SFRBU_25LDOCR]
+#endif
+       .endm
+
+       .macro at91_backup_set_lpm reg
+#ifdef CONFIG_SOC_SAMA7
+       orr     \reg, \reg, #0x200000
+#endif
+       .endm
+
        .text
 
        .arm
 
-/*
- * void at91_suspend_sram_fn(struct at91_pm_data*)
- * @input param:
- *     @r0: base address of struct at91_pm_data
+#ifdef CONFIG_SOC_SAMA7
+/**
+ * Enable self-refresh
+ *
+ * Side effects: overwrites r2, r3, tmp1, tmp2, tmp3, r7
  */
-/* at91_pm_suspend_in_sram must be 8-byte aligned per the requirements of fncpy() */
-       .align 3
-ENTRY(at91_pm_suspend_in_sram)
-       /* Save registers on stack */
-       stmfd   sp!, {r4 - r12, lr}
+.macro at91_sramc_self_refresh_ena
+       ldr     r2, .sramc_base
+       ldr     r3, .sramc_phy_base
+       ldr     r7, .pm_mode
 
-       /* Drain write buffer */
+       dsb
+
+       /* Disable all AXI ports. */
+       ldr     tmp1, [r2, #UDDRC_PCTRL_0]
+       bic     tmp1, tmp1, #0x1
+       str     tmp1, [r2, #UDDRC_PCTRL_0]
+
+       ldr     tmp1, [r2, #UDDRC_PCTRL_1]
+       bic     tmp1, tmp1, #0x1
+       str     tmp1, [r2, #UDDRC_PCTRL_1]
+
+       ldr     tmp1, [r2, #UDDRC_PCTRL_2]
+       bic     tmp1, tmp1, #0x1
+       str     tmp1, [r2, #UDDRC_PCTRL_2]
+
+       ldr     tmp1, [r2, #UDDRC_PCTRL_3]
+       bic     tmp1, tmp1, #0x1
+       str     tmp1, [r2, #UDDRC_PCTRL_3]
+
+       ldr     tmp1, [r2, #UDDRC_PCTRL_4]
+       bic     tmp1, tmp1, #0x1
+       str     tmp1, [r2, #UDDRC_PCTRL_4]
+
+sr_ena_1:
+       /* Wait for all ports to disable. */
+       ldr     tmp1, [r2, #UDDRC_PSTAT]
+       ldr     tmp2, =UDDRC_PSTAT_ALL_PORTS
+       tst     tmp1, tmp2
+       bne     sr_ena_1
+
+       /* Switch to self-refresh. */
+       ldr     tmp1, [r2, #UDDRC_PWRCTL]
+       orr     tmp1, tmp1, #UDDRC_PWRCTRL_SELFREF_SW
+       str     tmp1, [r2, #UDDRC_PWRCTL]
+
+sr_ena_2:
+       /* Wait for self-refresh enter. */
+       ldr     tmp1, [r2, #UDDRC_STAT]
+       bic     tmp1, tmp1, #~UDDRC_STAT_SELFREF_TYPE_MSK
+       cmp     tmp1, #UDDRC_STAT_SELFREF_TYPE_SW
+       bne     sr_ena_2
+
+       /* Put DDR PHY's DLL in bypass mode for non-backup modes. */
+       cmp     r7, #AT91_PM_BACKUP
+       beq     sr_ena_3
+       ldr     tmp1, [r3, #DDR3PHY_PIR]
+       orr     tmp1, tmp1, #DDR3PHY_PIR_DLLBYP
+       str     tmp1, [r3, #DDR3PHY_PIR]
+
+sr_ena_3:
+       /* Power down DDR PHY data receivers. */
+       ldr     tmp1, [r3, #DDR3PHY_DXCCR]
+       orr     tmp1, tmp1, #DDR3PHY_DXCCR_DXPDR
+       str     tmp1, [r3, #DDR3PHY_DXCCR]
+
+       /* Power down ADDR/CMD IO. */
+       ldr     tmp1, [r3, #DDR3PHY_ACIOCR]
+       orr     tmp1, tmp1, #DDR3PHY_ACIORC_ACPDD
+       orr     tmp1, tmp1, #DDR3PHY_ACIOCR_CKPDD_CK0
+       orr     tmp1, tmp1, #DDR3PHY_ACIOCR_CSPDD_CS0
+       str     tmp1, [r3, #DDR3PHY_ACIOCR]
+
+       /* Power down ODT. */
+       ldr     tmp1, [r3, #DDR3PHY_DSGCR]
+       orr     tmp1, tmp1, #DDR3PHY_DSGCR_ODTPDD_ODT0
+       str     tmp1, [r3, #DDR3PHY_DSGCR]
+.endm
+
+/**
+ * Disable self-refresh
+ *
+ * Side effects: overwrites r2, r3, tmp1, tmp2, tmp3
+ */
+.macro at91_sramc_self_refresh_dis
+       ldr     r2, .sramc_base
+       ldr     r3, .sramc_phy_base
+
+       /* Power up DDR PHY data receivers. */
+       ldr     tmp1, [r3, #DDR3PHY_DXCCR]
+       bic     tmp1, tmp1, #DDR3PHY_DXCCR_DXPDR
+       str     tmp1, [r3, #DDR3PHY_DXCCR]
+
+       /* Power up the output of CK and CS pins. */
+       ldr     tmp1, [r3, #DDR3PHY_ACIOCR]
+       bic     tmp1, tmp1, #DDR3PHY_ACIORC_ACPDD
+       bic     tmp1, tmp1, #DDR3PHY_ACIOCR_CKPDD_CK0
+       bic     tmp1, tmp1, #DDR3PHY_ACIOCR_CSPDD_CS0
+       str     tmp1, [r3, #DDR3PHY_ACIOCR]
+
+       /* Power up ODT. */
+       ldr     tmp1, [r3, #DDR3PHY_DSGCR]
+       bic     tmp1, tmp1, #DDR3PHY_DSGCR_ODTPDD_ODT0
+       str     tmp1, [r3, #DDR3PHY_DSGCR]
+
+       /* Take DDR PHY's DLL out of bypass mode. */
+       ldr     tmp1, [r3, #DDR3PHY_PIR]
+       bic     tmp1, tmp1, #DDR3PHY_PIR_DLLBYP
+       str     tmp1, [r3, #DDR3PHY_PIR]
+
+       /* Enable quasi-dynamic programming. */
        mov     tmp1, #0
-       mcr     p15, 0, tmp1, c7, c10, 4
+       str     tmp1, [r2, #UDDRC_SWCTRL]
+
+       /* De-assert SDRAM initialization. */
+       ldr     tmp1, [r2, #UDDRC_DFIMISC]
+       bic     tmp1, tmp1, #UDDRC_DFIMISC_DFI_INIT_COMPLETE_EN
+       str     tmp1, [r2, #UDDRC_DFIMISC]
+
+       /* Quasi-dynamic programming done. */
+       mov     tmp1, #UDDRC_SWCTRL_SW_DONE
+       str     tmp1, [r2, #UDDRC_SWCTRL]
+
+sr_dis_1:
+       ldr     tmp1, [r2, #UDDRC_SWSTAT]
+       tst     tmp1, #UDDRC_SWSTAT_SW_DONE_ACK
+       beq     sr_dis_1
+
+       /* DLL soft-reset + DLL lock wait + ITM reset */
+       mov     tmp1, #(DDR3PHY_PIR_INIT | DDR3PHY_PIR_DLLSRST | \
+                       DDR3PHY_PIR_DLLLOCK | DDR3PHY_PIR_ITMSRST)
+       str     tmp1, [r3, #DDR3PHY_PIR]
+
+sr_dis_4:
+       /* Wait for it. */
+       ldr     tmp1, [r3, #DDR3PHY_PGSR]
+       tst     tmp1, #DDR3PHY_PGSR_IDONE
+       beq     sr_dis_4
+
+       /* Enable quasi-dynamic programming. */
+       mov     tmp1, #0
+       str     tmp1, [r2, #UDDRC_SWCTRL]
+
+       /* Assert PHY init complete enable signal. */
+       ldr     tmp1, [r2, #UDDRC_DFIMISC]
+       orr     tmp1, tmp1, #UDDRC_DFIMISC_DFI_INIT_COMPLETE_EN
+       str     tmp1, [r2, #UDDRC_DFIMISC]
+
+       /* Programming is done. Set sw_done. */
+       mov     tmp1, #UDDRC_SWCTRL_SW_DONE
+       str     tmp1, [r2, #UDDRC_SWCTRL]
+
+sr_dis_5:
+       /* Wait for it. */
+       ldr     tmp1, [r2, #UDDRC_SWSTAT]
+       tst     tmp1, #UDDRC_SWSTAT_SW_DONE_ACK
+       beq     sr_dis_5
+
+       /* Trigger self-refresh exit. */
+       ldr     tmp1, [r2, #UDDRC_PWRCTL]
+       bic     tmp1, tmp1, #UDDRC_PWRCTRL_SELFREF_SW
+       str     tmp1, [r2, #UDDRC_PWRCTL]
+
+sr_dis_6:
+       /* Wait for self-refresh exit done. */
+       ldr     tmp1, [r2, #UDDRC_STAT]
+       bic     tmp1, tmp1, #~UDDRC_STAT_OPMODE_MSK
+       cmp     tmp1, #UDDRC_STAT_OPMODE_NORMAL
+       bne     sr_dis_6
+
+       /* Enable all AXI ports. */
+       ldr     tmp1, [r2, #UDDRC_PCTRL_0]
+       orr     tmp1, tmp1, #0x1
+       str     tmp1, [r2, #UDDRC_PCTRL_0]
+
+       ldr     tmp1, [r2, #UDDRC_PCTRL_1]
+       orr     tmp1, tmp1, #0x1
+       str     tmp1, [r2, #UDDRC_PCTRL_1]
+
+       ldr     tmp1, [r2, #UDDRC_PCTRL_2]
+       orr     tmp1, tmp1, #0x1
+       str     tmp1, [r2, #UDDRC_PCTRL_2]
+
+       ldr     tmp1, [r2, #UDDRC_PCTRL_3]
+       orr     tmp1, tmp1, #0x1
+       str     tmp1, [r2, #UDDRC_PCTRL_3]
+
+       ldr     tmp1, [r2, #UDDRC_PCTRL_4]
+       orr     tmp1, tmp1, #0x1
+       str     tmp1, [r2, #UDDRC_PCTRL_4]
 
-       ldr     tmp1, [r0, #PM_DATA_PMC]
-       str     tmp1, .pmc_base
-       ldr     tmp1, [r0, #PM_DATA_RAMC0]
-       str     tmp1, .sramc_base
-       ldr     tmp1, [r0, #PM_DATA_RAMC1]
-       str     tmp1, .sramc1_base
-       ldr     tmp1, [r0, #PM_DATA_MEMCTRL]
-       str     tmp1, .memtype
-       ldr     tmp1, [r0, #PM_DATA_MODE]
-       str     tmp1, .pm_mode
-       ldr     tmp1, [r0, #PM_DATA_PMC_MCKR_OFFSET]
-       str     tmp1, .mckr_offset
-       ldr     tmp1, [r0, #PM_DATA_PMC_VERSION]
-       str     tmp1, .pmc_version
-       /* Both ldrne below are here to preload their address in the TLB */
-       ldr     tmp1, [r0, #PM_DATA_SHDWC]
-       str     tmp1, .shdwc
-       cmp     tmp1, #0
-       ldrne   tmp2, [tmp1, #0]
-       ldr     tmp1, [r0, #PM_DATA_SFRBU]
-       str     tmp1, .sfrbu
-       cmp     tmp1, #0
-       ldrne   tmp2, [tmp1, #0x10]
+       dsb
+.endm
+#else
+/**
+ * Enable self-refresh
+ *
+ * register usage:
+ *     @r1: memory type
+ *     @r2: base address of the sram controller
+ *     @r3: temporary
+ */
+.macro at91_sramc_self_refresh_ena
+       ldr     r1, .memtype
+       ldr     r2, .sramc_base
 
-       /* Active the self-refresh mode */
-       mov     r0, #SRAMC_SELF_FRESH_ACTIVE
-       bl      at91_sramc_self_refresh
+       cmp     r1, #AT91_MEMCTRL_MC
+       bne     sr_ena_ddrc_sf
 
-       ldr     r0, .pm_mode
-       cmp     r0, #AT91_PM_STANDBY
-       beq     standby
-       cmp     r0, #AT91_PM_BACKUP
-       beq     backup_mode
+       /* Active SDRAM self-refresh mode */
+       mov     r3, #1
+       str     r3, [r2, #AT91_MC_SDRAMC_SRR]
+       b       sr_ena_exit
 
-       bl      at91_ulp_mode
-       b       exit_suspend
+sr_ena_ddrc_sf:
+       cmp     r1, #AT91_MEMCTRL_DDRSDR
+       bne     sr_ena_sdramc_sf
 
-standby:
-       /* Wait for interrupt */
-       ldr     pmc, .pmc_base
-       at91_cpu_idle
-       b       exit_suspend
+       /*
+        * DDR Memory controller
+        */
 
-backup_mode:
-       bl      at91_backup_mode
-       b       exit_suspend
+       /* LPDDR1 --> force DDR2 mode during self-refresh */
+       ldr     r3, [r2, #AT91_DDRSDRC_MDR]
+       str     r3, .saved_sam9_mdr
+       bic     r3, r3, #~AT91_DDRSDRC_MD
+       cmp     r3, #AT91_DDRSDRC_MD_LOW_POWER_DDR
+       ldreq   r3, [r2, #AT91_DDRSDRC_MDR]
+       biceq   r3, r3, #AT91_DDRSDRC_MD
+       orreq   r3, r3, #AT91_DDRSDRC_MD_DDR2
+       streq   r3, [r2, #AT91_DDRSDRC_MDR]
 
-exit_suspend:
-       /* Exit the self-refresh mode */
-       mov     r0, #SRAMC_SELF_FRESH_EXIT
-       bl      at91_sramc_self_refresh
+       /* Active DDRC self-refresh mode */
+       ldr     r3, [r2, #AT91_DDRSDRC_LPR]
+       str     r3, .saved_sam9_lpr
+       bic     r3, r3, #AT91_DDRSDRC_LPCB
+       orr     r3, r3, #AT91_DDRSDRC_LPCB_SELF_REFRESH
+       str     r3, [r2, #AT91_DDRSDRC_LPR]
 
-       /* Restore registers, and return */
-       ldmfd   sp!, {r4 - r12, pc}
-ENDPROC(at91_pm_suspend_in_sram)
+       /* If using the 2nd ddr controller */
+       ldr     r2, .sramc1_base
+       cmp     r2, #0
+       beq     sr_ena_no_2nd_ddrc
 
-ENTRY(at91_backup_mode)
-       /* Switch the master clock source to slow clock. */
-       ldr     pmc, .pmc_base
-       ldr     tmp2, .mckr_offset
-       ldr     tmp1, [pmc, tmp2]
-       bic     tmp1, tmp1, #AT91_PMC_CSS
-       str     tmp1, [pmc, tmp2]
+       ldr     r3, [r2, #AT91_DDRSDRC_MDR]
+       str     r3, .saved_sam9_mdr1
+       bic     r3, r3, #~AT91_DDRSDRC_MD
+       cmp     r3, #AT91_DDRSDRC_MD_LOW_POWER_DDR
+       ldreq   r3, [r2, #AT91_DDRSDRC_MDR]
+       biceq   r3, r3, #AT91_DDRSDRC_MD
+       orreq   r3, r3, #AT91_DDRSDRC_MD_DDR2
+       streq   r3, [r2, #AT91_DDRSDRC_MDR]
 
-       wait_mckrdy
+       /* Active DDRC self-refresh mode */
+       ldr     r3, [r2, #AT91_DDRSDRC_LPR]
+       str     r3, .saved_sam9_lpr1
+       bic     r3, r3, #AT91_DDRSDRC_LPCB
+       orr     r3, r3, #AT91_DDRSDRC_LPCB_SELF_REFRESH
+       str     r3, [r2, #AT91_DDRSDRC_LPR]
 
-       /*BUMEN*/
-       ldr     r0, .sfrbu
-       mov     tmp1, #0x1
-       str     tmp1, [r0, #0x10]
+sr_ena_no_2nd_ddrc:
+       b       sr_ena_exit
 
-       /* Shutdown */
-       ldr     r0, .shdwc
-       mov     tmp1, #0xA5000000
-       add     tmp1, tmp1, #0x1
-       str     tmp1, [r0, #0]
-ENDPROC(at91_backup_mode)
+       /*
+        * SDRAMC Memory controller
+        */
+sr_ena_sdramc_sf:
+       /* Active SDRAMC self-refresh mode */
+       ldr     r3, [r2, #AT91_SDRAMC_LPR]
+       str     r3, .saved_sam9_lpr
+       bic     r3, r3, #AT91_SDRAMC_LPCB
+       orr     r3, r3, #AT91_SDRAMC_LPCB_SELF_REFRESH
+       str     r3, [r2, #AT91_SDRAMC_LPR]
+
+       ldr     r3, .saved_sam9_lpr
+       str     r3, [r2, #AT91_SDRAMC_LPR]
+
+sr_ena_exit:
+.endm
+
+/**
+ * Disable self-refresh
+ *
+ * register usage:
+ *     @r1: memory type
+ *     @r2: base address of the sram controller
+ *     @r3: temporary
+ */
+.macro at91_sramc_self_refresh_dis
+       ldr     r1, .memtype
+       ldr     r2, .sramc_base
+
+       cmp     r1, #AT91_MEMCTRL_MC
+       bne     sr_dis_ddrc_exit_sf
+
+       /*
+        * at91rm9200 Memory controller
+        */
+
+        /*
+         * For exiting the self-refresh mode, do nothing,
+         * automatically exit the self-refresh mode.
+         */
+       b       sr_dis_exit
+
+sr_dis_ddrc_exit_sf:
+       cmp     r1, #AT91_MEMCTRL_DDRSDR
+       bne     sdramc_exit_sf
+
+       /* DDR Memory controller */
+
+       /* Restore MDR in case of LPDDR1 */
+       ldr     r3, .saved_sam9_mdr
+       str     r3, [r2, #AT91_DDRSDRC_MDR]
+       /* Restore LPR on AT91 with DDRAM */
+       ldr     r3, .saved_sam9_lpr
+       str     r3, [r2, #AT91_DDRSDRC_LPR]
+
+       /* If using the 2nd ddr controller */
+       ldr     r2, .sramc1_base
+       cmp     r2, #0
+       ldrne   r3, .saved_sam9_mdr1
+       strne   r3, [r2, #AT91_DDRSDRC_MDR]
+       ldrne   r3, .saved_sam9_lpr1
+       strne   r3, [r2, #AT91_DDRSDRC_LPR]
+
+       b       sr_dis_exit
+
+sdramc_exit_sf:
+       /* SDRAMC Memory controller */
+       ldr     r3, .saved_sam9_lpr
+       str     r3, [r2, #AT91_SDRAMC_LPR]
+
+sr_dis_exit:
+.endm
+#endif
 
 .macro at91_pm_ulp0_mode
        ldr     pmc, .pmc_base
@@ -176,7 +467,9 @@ ENDPROC(at91_backup_mode)
        bic     tmp1, tmp1, #AT91_PMC_PRES
        orr     tmp1, tmp1, #AT91_PMC_PRES_64
        str     tmp1, [pmc, tmp3]
-       wait_mckrdy
+
+       mov     tmp3, #0
+       wait_mckrdy tmp3
        b       1f
 
 0:
@@ -212,10 +505,13 @@ ENDPROC(at91_backup_mode)
        bne     5f
 
        /* Set lowest prescaler for fast resume. */
+       ldr     tmp3, .mckr_offset
        ldr     tmp1, [pmc, tmp3]
        bic     tmp1, tmp1, #AT91_PMC_PRES
        str     tmp1, [pmc, tmp3]
-       wait_mckrdy
+
+       mov     tmp3, #0
+       wait_mckrdy tmp3
        b       6f
 
 5:     /* Restore RC oscillator state */
@@ -252,6 +548,7 @@ ENDPROC(at91_backup_mode)
 .macro at91_pm_ulp1_mode
        ldr     pmc, .pmc_base
        ldr     tmp2, .mckr_offset
+       mov     tmp3, #0
 
        /* Save RC oscillator state and check if it is enabled. */
        ldr     tmp1, [pmc, #AT91_PMC_SR]
@@ -293,7 +590,7 @@ ENDPROC(at91_backup_mode)
        orr     tmp1, tmp1, #AT91_PMC_CSS_MAIN
        str     tmp1, [pmc, tmp2]
 
-       wait_mckrdy
+       wait_mckrdy tmp3
 
        /* Enter the ULP1 mode by set WAITMODE bit in CKGR_MOR */
        ldr     tmp1, [pmc, #AT91_CKGR_MOR]
@@ -306,7 +603,7 @@ ENDPROC(at91_backup_mode)
        nop
        nop
 
-       wait_mckrdy
+       wait_mckrdy tmp3
 
        /* Enable the crystal oscillator */
        ldr     tmp1, [pmc, #AT91_CKGR_MOR]
@@ -322,7 +619,7 @@ ENDPROC(at91_backup_mode)
        bic     tmp1, tmp1, #AT91_PMC_CSS
        str     tmp1, [pmc, tmp2]
 
-       wait_mckrdy
+       wait_mckrdy tmp3
 
        /* Switch main clock source to crystal oscillator */
        ldr     tmp1, [pmc, #AT91_CKGR_MOR]
@@ -339,7 +636,7 @@ ENDPROC(at91_backup_mode)
        orr     tmp1, tmp1, #AT91_PMC_CSS_MAIN
        str     tmp1, [pmc, tmp2]
 
-       wait_mckrdy
+       wait_mckrdy tmp3
 
        /* Restore RC oscillator state */
        ldr     tmp1, .saved_osc_status
@@ -367,7 +664,7 @@ ENDPROC(at91_backup_mode)
        cmp     tmp1, #AT91_PMC_V1
        beq     1f
 
-#ifdef CONFIG_SOC_SAM9X60
+#ifdef CONFIG_HAVE_AT91_SAM9X60_PLL
        /* Save PLLA settings. */
        ldr     tmp2, [pmc, #AT91_PMC_PLL_UPDT]
        bic     tmp2, tmp2, #AT91_PMC_PLL_UPDT_ID
@@ -434,7 +731,7 @@ ENDPROC(at91_backup_mode)
        cmp     tmp3, #AT91_PMC_V1
        beq     4f
 
-#ifdef CONFIG_SOC_SAM9X60
+#ifdef CONFIG_HAVE_AT91_SAM9X60_PLL
        /* step 1. */
        ldr     tmp1, [pmc, #AT91_PMC_PLL_UPDT]
        bic     tmp1, tmp1, #AT91_PMC_PLL_UPDT_ID
@@ -497,7 +794,122 @@ ENDPROC(at91_backup_mode)
 2:
 .endm
 
-ENTRY(at91_ulp_mode)
+/**
+ * at91_mckx_ps_enable:        save MCK1..4 settings and switch it to main clock
+ *
+ * Side effects: overwrites tmp1, tmp2
+ */
+.macro at91_mckx_ps_enable
+#ifdef CONFIG_SOC_SAMA7
+       ldr     pmc, .pmc_base
+
+       /* There are 4 MCKs we need to handle: MCK1..4 */
+       mov     tmp1, #1
+e_loop:        cmp     tmp1, #5
+       beq     e_done
+
+       /* Write MCK ID to retrieve the settings. */
+       str     tmp1, [pmc, #AT91_PMC_MCR_V2]
+       ldr     tmp2, [pmc, #AT91_PMC_MCR_V2]
+
+e_save_mck1:
+       cmp     tmp1, #1
+       bne     e_save_mck2
+       str     tmp2, .saved_mck1
+       b       e_ps
+
+e_save_mck2:
+       cmp     tmp1, #2
+       bne     e_save_mck3
+       str     tmp2, .saved_mck2
+       b       e_ps
+
+e_save_mck3:
+       cmp     tmp1, #3
+       bne     e_save_mck4
+       str     tmp2, .saved_mck3
+       b       e_ps
+
+e_save_mck4:
+       str     tmp2, .saved_mck4
+
+e_ps:
+       /* Use CSS=MAINCK and DIV=1. */
+       bic     tmp2, tmp2, #AT91_PMC_MCR_V2_CSS
+       bic     tmp2, tmp2, #AT91_PMC_MCR_V2_DIV
+       orr     tmp2, tmp2, #AT91_PMC_MCR_V2_CSS_MAINCK
+       orr     tmp2, tmp2, #AT91_PMC_MCR_V2_DIV1
+       str     tmp2, [pmc, #AT91_PMC_MCR_V2]
+
+       wait_mckrdy tmp1
+
+       add     tmp1, tmp1, #1
+       b       e_loop
+
+e_done:
+#endif
+.endm
+
+/**
+ * at91_mckx_ps_restore: restore MCK1..4 settings
+ *
+ * Side effects: overwrites tmp1, tmp2
+ */
+.macro at91_mckx_ps_restore
+#ifdef CONFIG_SOC_SAMA7
+       ldr     pmc, .pmc_base
+
+       /* There are 4 MCKs we need to handle: MCK1..4 */
+       mov     tmp1, #1
+r_loop:        cmp     tmp1, #5
+       beq     r_done
+
+r_save_mck1:
+       cmp     tmp1, #1
+       bne     r_save_mck2
+       ldr     tmp2, .saved_mck1
+       b       r_ps
+
+r_save_mck2:
+       cmp     tmp1, #2
+       bne     r_save_mck3
+       ldr     tmp2, .saved_mck2
+       b       r_ps
+
+r_save_mck3:
+       cmp     tmp1, #3
+       bne     r_save_mck4
+       ldr     tmp2, .saved_mck3
+       b       r_ps
+
+r_save_mck4:
+       ldr     tmp2, .saved_mck4
+
+r_ps:
+       /* Write MCK ID to retrieve the settings. */
+       str     tmp1, [pmc, #AT91_PMC_MCR_V2]
+       ldr     tmp3, [pmc, #AT91_PMC_MCR_V2]
+
+       /* We need to restore CSS and DIV. */
+       bic     tmp3, tmp3, #AT91_PMC_MCR_V2_CSS
+       bic     tmp3, tmp3, #AT91_PMC_MCR_V2_DIV
+       orr     tmp3, tmp3, tmp2
+       bic     tmp3, tmp3, #AT91_PMC_MCR_V2_ID_MSK
+       orr     tmp3, tmp3, tmp1
+       orr     tmp3, tmp3, #AT91_PMC_MCR_V2_CMD
+       str     tmp2, [pmc, #AT91_PMC_MCR_V2]
+
+       wait_mckrdy tmp1
+
+       add     tmp1, tmp1, #1
+       b       r_loop
+r_done:
+#endif
+.endm
+
+.macro at91_ulp_mode
+       at91_mckx_ps_enable
+
        ldr     pmc, .pmc_base
        ldr     tmp2, .mckr_offset
        ldr     tmp3, .pm_mode
@@ -518,10 +930,15 @@ ENTRY(at91_ulp_mode)
 save_mck:
        str     tmp1, [pmc, tmp2]
 
-       wait_mckrdy
+       mov     tmp3, #0
+       wait_mckrdy tmp3
 
        at91_plla_disable
 
+       /* Enable low power mode for 2.5V regulator. */
+       at91_2_5V_reg_set_low_power 1
+
+       ldr     tmp3, .pm_mode
        cmp     tmp3, #AT91_PM_ULP1
        beq     ulp1_mode
 
@@ -533,6 +950,9 @@ ulp1_mode:
        b       ulp_exit
 
 ulp_exit:
+       /* Disable low power mode for 2.5V regulator. */
+       at91_2_5V_reg_set_low_power 0
+
        ldr     pmc, .pmc_base
 
        at91_plla_enable
@@ -544,135 +964,110 @@ ulp_exit:
        ldr     tmp2, .saved_mckr
        str     tmp2, [pmc, tmp1]
 
-       wait_mckrdy
-
-       mov     pc, lr
-ENDPROC(at91_ulp_mode)
+       mov     tmp3, #0
+       wait_mckrdy tmp3
 
-/*
- * void at91_sramc_self_refresh(unsigned int is_active)
- *
- * @input param:
- *     @r0: 1 - active self-refresh mode
- *          0 - exit self-refresh mode
- * register usage:
- *     @r1: memory type
- *     @r2: base address of the sram controller
- */
-
-ENTRY(at91_sramc_self_refresh)
-       ldr     r1, .memtype
-       ldr     r2, .sramc_base
-
-       cmp     r1, #AT91_MEMCTRL_MC
-       bne     ddrc_sf
-
-       /*
-        * at91rm9200 Memory controller
-        */
-
-        /*
-         * For exiting the self-refresh mode, do nothing,
-         * automatically exit the self-refresh mode.
-         */
-       tst     r0, #SRAMC_SELF_FRESH_ACTIVE
-       beq     exit_sramc_sf
-
-       /* Active SDRAM self-refresh mode */
-       mov     r3, #1
-       str     r3, [r2, #AT91_MC_SDRAMC_SRR]
-       b       exit_sramc_sf
+       at91_mckx_ps_restore
+.endm
 
-ddrc_sf:
-       cmp     r1, #AT91_MEMCTRL_DDRSDR
-       bne     sdramc_sf
+.macro at91_backup_mode
+       /* Switch the master clock source to slow clock. */
+       ldr     pmc, .pmc_base
+       ldr     tmp2, .mckr_offset
+       ldr     tmp1, [pmc, tmp2]
+       bic     tmp1, tmp1, #AT91_PMC_CSS
+       str     tmp1, [pmc, tmp2]
 
-       /*
-        * DDR Memory controller
-        */
-       tst     r0, #SRAMC_SELF_FRESH_ACTIVE
-       beq     ddrc_exit_sf
+       mov     tmp3, #0
+       wait_mckrdy tmp3
 
-       /* LPDDR1 --> force DDR2 mode during self-refresh */
-       ldr     r3, [r2, #AT91_DDRSDRC_MDR]
-       str     r3, .saved_sam9_mdr
-       bic     r3, r3, #~AT91_DDRSDRC_MD
-       cmp     r3, #AT91_DDRSDRC_MD_LOW_POWER_DDR
-       ldreq   r3, [r2, #AT91_DDRSDRC_MDR]
-       biceq   r3, r3, #AT91_DDRSDRC_MD
-       orreq   r3, r3, #AT91_DDRSDRC_MD_DDR2
-       streq   r3, [r2, #AT91_DDRSDRC_MDR]
+       /*BUMEN*/
+       ldr     r0, .sfrbu
+       mov     tmp1, #0x1
+       str     tmp1, [r0, #0x10]
 
-       /* Active DDRC self-refresh mode */
-       ldr     r3, [r2, #AT91_DDRSDRC_LPR]
-       str     r3, .saved_sam9_lpr
-       bic     r3, r3, #AT91_DDRSDRC_LPCB
-       orr     r3, r3, #AT91_DDRSDRC_LPCB_SELF_REFRESH
-       str     r3, [r2, #AT91_DDRSDRC_LPR]
+       /* Wait for it. */
+1:     ldr     tmp1, [r0, #0x10]
+       tst     tmp1, #0x1
+       beq     1b
 
-       /* If using the 2nd ddr controller */
-       ldr     r2, .sramc1_base
-       cmp     r2, #0
-       beq     no_2nd_ddrc
+       /* Shutdown */
+       ldr     r0, .shdwc
+       mov     tmp1, #0xA5000000
+       add     tmp1, tmp1, #0x1
+       at91_backup_set_lpm tmp1
+       str     tmp1, [r0, #0]
+.endm
 
-       ldr     r3, [r2, #AT91_DDRSDRC_MDR]
-       str     r3, .saved_sam9_mdr1
-       bic     r3, r3, #~AT91_DDRSDRC_MD
-       cmp     r3, #AT91_DDRSDRC_MD_LOW_POWER_DDR
-       ldreq   r3, [r2, #AT91_DDRSDRC_MDR]
-       biceq   r3, r3, #AT91_DDRSDRC_MD
-       orreq   r3, r3, #AT91_DDRSDRC_MD_DDR2
-       streq   r3, [r2, #AT91_DDRSDRC_MDR]
+/*
+ * void at91_suspend_sram_fn(struct at91_pm_data*)
+ * @input param:
+ *     @r0: base address of struct at91_pm_data
+ */
+/* at91_pm_suspend_in_sram must be 8-byte aligned per the requirements of fncpy() */
+       .align 3
+ENTRY(at91_pm_suspend_in_sram)
+       /* Save registers on stack */
+       stmfd   sp!, {r4 - r12, lr}
 
-       /* Active DDRC self-refresh mode */
-       ldr     r3, [r2, #AT91_DDRSDRC_LPR]
-       str     r3, .saved_sam9_lpr1
-       bic     r3, r3, #AT91_DDRSDRC_LPCB
-       orr     r3, r3, #AT91_DDRSDRC_LPCB_SELF_REFRESH
-       str     r3, [r2, #AT91_DDRSDRC_LPR]
+       /* Drain write buffer */
+       mov     tmp1, #0
+       mcr     p15, 0, tmp1, c7, c10, 4
 
-no_2nd_ddrc:
-       b       exit_sramc_sf
+       ldr     tmp1, [r0, #PM_DATA_PMC]
+       str     tmp1, .pmc_base
+       ldr     tmp1, [r0, #PM_DATA_RAMC0]
+       str     tmp1, .sramc_base
+       ldr     tmp1, [r0, #PM_DATA_RAMC1]
+       str     tmp1, .sramc1_base
+       ldr     tmp1, [r0, #PM_DATA_RAMC_PHY]
+       str     tmp1, .sramc_phy_base
+       ldr     tmp1, [r0, #PM_DATA_MEMCTRL]
+       str     tmp1, .memtype
+       ldr     tmp1, [r0, #PM_DATA_MODE]
+       str     tmp1, .pm_mode
+       ldr     tmp1, [r0, #PM_DATA_PMC_MCKR_OFFSET]
+       str     tmp1, .mckr_offset
+       ldr     tmp1, [r0, #PM_DATA_PMC_VERSION]
+       str     tmp1, .pmc_version
+       /* Both ldrne below are here to preload their address in the TLB */
+       ldr     tmp1, [r0, #PM_DATA_SHDWC]
+       str     tmp1, .shdwc
+       cmp     tmp1, #0
+       ldrne   tmp2, [tmp1, #0]
+       ldr     tmp1, [r0, #PM_DATA_SFRBU]
+       str     tmp1, .sfrbu
+       cmp     tmp1, #0
+       ldrne   tmp2, [tmp1, #0x10]
 
-ddrc_exit_sf:
-       /* Restore MDR in case of LPDDR1 */
-       ldr     r3, .saved_sam9_mdr
-       str     r3, [r2, #AT91_DDRSDRC_MDR]
-       /* Restore LPR on AT91 with DDRAM */
-       ldr     r3, .saved_sam9_lpr
-       str     r3, [r2, #AT91_DDRSDRC_LPR]
+       /* Active the self-refresh mode */
+       at91_sramc_self_refresh_ena
 
-       /* If using the 2nd ddr controller */
-       ldr     r2, .sramc1_base
-       cmp     r2, #0
-       ldrne   r3, .saved_sam9_mdr1
-       strne   r3, [r2, #AT91_DDRSDRC_MDR]
-       ldrne   r3, .saved_sam9_lpr1
-       strne   r3, [r2, #AT91_DDRSDRC_LPR]
+       ldr     r0, .pm_mode
+       cmp     r0, #AT91_PM_STANDBY
+       beq     standby
+       cmp     r0, #AT91_PM_BACKUP
+       beq     backup_mode
 
-       b       exit_sramc_sf
+       at91_ulp_mode
+       b       exit_suspend
 
-       /*
-        * SDRAMC Memory controller
-        */
-sdramc_sf:
-       tst     r0, #SRAMC_SELF_FRESH_ACTIVE
-       beq     sdramc_exit_sf
+standby:
+       /* Wait for interrupt */
+       ldr     pmc, .pmc_base
+       at91_cpu_idle
+       b       exit_suspend
 
-       /* Active SDRAMC self-refresh mode */
-       ldr     r3, [r2, #AT91_SDRAMC_LPR]
-       str     r3, .saved_sam9_lpr
-       bic     r3, r3, #AT91_SDRAMC_LPCB
-       orr     r3, r3, #AT91_SDRAMC_LPCB_SELF_REFRESH
-       str     r3, [r2, #AT91_SDRAMC_LPR]
+backup_mode:
+       at91_backup_mode
 
-sdramc_exit_sf:
-       ldr     r3, .saved_sam9_lpr
-       str     r3, [r2, #AT91_SDRAMC_LPR]
+exit_suspend:
+       /* Exit the self-refresh mode */
+       at91_sramc_self_refresh_dis
 
-exit_sramc_sf:
-       mov     pc, lr
-ENDPROC(at91_sramc_self_refresh)
+       /* Restore registers, and return */
+       ldmfd   sp!, {r4 - r12, pc}
+ENDPROC(at91_pm_suspend_in_sram)
 
 .pmc_base:
        .word 0
@@ -680,6 +1075,8 @@ ENDPROC(at91_sramc_self_refresh)
        .word 0
 .sramc1_base:
        .word 0
+.sramc_phy_base:
+       .word 0
 .shdwc:
        .word 0
 .sfrbu:
@@ -706,6 +1103,16 @@ ENDPROC(at91_sramc_self_refresh)
        .word 0
 .saved_osc_status:
        .word 0
+#ifdef CONFIG_SOC_SAMA7
+.saved_mck1:
+       .word 0
+.saved_mck2:
+       .word 0
+.saved_mck3:
+       .word 0
+.saved_mck4:
+       .word 0
+#endif
 
 ENTRY(at91_pm_suspend_in_sram_sz)
        .word .-at91_pm_suspend_in_sram