Merge tag 'for-5.15/parisc' of git://git.kernel.org/pub/scm/linux/kernel/git/deller...
[linux-2.6-microblaze.git] / arch / arm / mach-at91 / pm_suspend.S
index 960ad29..cbd61a3 100644 (file)
@@ -22,11 +22,23 @@ 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
 
 /*
@@ -71,10 +83,233 @@ 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
 
+#ifdef CONFIG_SOC_SAMA7
+/**
+ * Enable self-refresh
+ *
+ * Side effects: overwrites r2, r3, tmp1, tmp2, tmp3, r7
+ */
+.macro at91_sramc_self_refresh_ena
+       ldr     r2, .sramc_base
+       ldr     r3, .sramc_phy_base
+       ldr     r7, .pm_mode
+
+       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
+       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]
+
+       dsb
+.endm
+#else
 /**
  * Enable self-refresh
  *
@@ -216,6 +451,7 @@ sdramc_exit_sf:
 
 sr_dis_exit:
 .endm
+#endif
 
 .macro at91_pm_ulp0_mode
        ldr     pmc, .pmc_base
@@ -231,7 +467,9 @@ sr_dis_exit:
        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:
@@ -267,10 +505,13 @@ sr_dis_exit:
        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 */
@@ -307,6 +548,7 @@ sr_dis_exit:
 .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]
@@ -348,7 +590,7 @@ sr_dis_exit:
        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]
@@ -361,7 +603,7 @@ sr_dis_exit:
        nop
        nop
 
-       wait_mckrdy
+       wait_mckrdy tmp3
 
        /* Enable the crystal oscillator */
        ldr     tmp1, [pmc, #AT91_CKGR_MOR]
@@ -377,7 +619,7 @@ sr_dis_exit:
        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]
@@ -394,7 +636,7 @@ sr_dis_exit:
        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
@@ -422,7 +664,7 @@ sr_dis_exit:
        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
@@ -489,7 +731,7 @@ sr_dis_exit:
        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
@@ -552,7 +794,122 @@ sr_dis_exit:
 2:
 .endm
 
+/**
+ * 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
@@ -573,10 +930,15 @@ sr_dis_exit:
 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
 
@@ -588,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
@@ -599,8 +964,10 @@ ulp_exit:
        ldr     tmp2, .saved_mckr
        str     tmp2, [pmc, tmp1]
 
-       wait_mckrdy
+       mov     tmp3, #0
+       wait_mckrdy tmp3
 
+       at91_mckx_ps_restore
 .endm
 
 .macro at91_backup_mode
@@ -611,17 +978,24 @@ ulp_exit:
        bic     tmp1, tmp1, #AT91_PMC_CSS
        str     tmp1, [pmc, tmp2]
 
-       wait_mckrdy
+       mov     tmp3, #0
+       wait_mckrdy tmp3
 
        /*BUMEN*/
        ldr     r0, .sfrbu
        mov     tmp1, #0x1
        str     tmp1, [r0, #0x10]
 
+       /* Wait for it. */
+1:     ldr     tmp1, [r0, #0x10]
+       tst     tmp1, #0x1
+       beq     1b
+
        /* Shutdown */
        ldr     r0, .shdwc
        mov     tmp1, #0xA5000000
        add     tmp1, tmp1, #0x1
+       at91_backup_set_lpm tmp1
        str     tmp1, [r0, #0]
 .endm
 
@@ -646,6 +1020,8 @@ ENTRY(at91_pm_suspend_in_sram)
        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]
@@ -699,6 +1075,8 @@ ENDPROC(at91_pm_suspend_in_sram)
        .word 0
 .sramc1_base:
        .word 0
+.sramc_phy_base:
+       .word 0
 .shdwc:
        .word 0
 .sfrbu:
@@ -725,6 +1103,16 @@ ENDPROC(at91_pm_suspend_in_sram)
        .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