ARM: at91: pm: avoid push and pop on stack while memory is in self-refersh
For the previous AT91 RAM controller and self-refresh procedure this had no side effects. However, for SAMA7G5 the self-refresh procedure doesn't allow this anymore as the RAM controller ports are closed before switching it to self-refresh. This commits prepares the code for the following ones adding self-refresh and PM support for SAMA7G5. Signed-off-by: Claudiu Beznea <claudiu.beznea@microchip.com> Signed-off-by: Nicolas Ferre <nicolas.ferre@microchip.com> Link: https://lore.kernel.org/r/20210415105010.569620-8-claudiu.beznea@microchip.com
This commit is contained in:
parent
29cdf077a9
commit
87e1b30c29
1 changed files with 206 additions and 193 deletions
|
@ -75,98 +75,147 @@ tmp3 .req r6
|
||||||
|
|
||||||
.arm
|
.arm
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* void at91_suspend_sram_fn(struct at91_pm_data*)
|
* Enable self-refresh
|
||||||
* @input param:
|
*
|
||||||
* @r0: base address of struct at91_pm_data
|
* register usage:
|
||||||
|
* @r1: memory type
|
||||||
|
* @r2: base address of the sram controller
|
||||||
|
* @r3: temporary
|
||||||
*/
|
*/
|
||||||
/* at91_pm_suspend_in_sram must be 8-byte aligned per the requirements of fncpy() */
|
.macro at91_sramc_self_refresh_ena
|
||||||
.align 3
|
ldr r1, .memtype
|
||||||
ENTRY(at91_pm_suspend_in_sram)
|
ldr r2, .sramc_base
|
||||||
/* Save registers on stack */
|
|
||||||
stmfd sp!, {r4 - r12, lr}
|
|
||||||
|
|
||||||
/* Drain write buffer */
|
cmp r1, #AT91_MEMCTRL_MC
|
||||||
mov tmp1, #0
|
bne sr_ena_ddrc_sf
|
||||||
mcr p15, 0, tmp1, c7, c10, 4
|
|
||||||
|
|
||||||
ldr tmp1, [r0, #PM_DATA_PMC]
|
/* Active SDRAM self-refresh mode */
|
||||||
str tmp1, .pmc_base
|
mov r3, #1
|
||||||
ldr tmp1, [r0, #PM_DATA_RAMC0]
|
str r3, [r2, #AT91_MC_SDRAMC_SRR]
|
||||||
str tmp1, .sramc_base
|
b sr_ena_exit
|
||||||
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]
|
|
||||||
|
|
||||||
/* Active the self-refresh mode */
|
sr_ena_ddrc_sf:
|
||||||
mov r0, #SRAMC_SELF_FRESH_ACTIVE
|
cmp r1, #AT91_MEMCTRL_DDRSDR
|
||||||
bl at91_sramc_self_refresh
|
bne sr_ena_sdramc_sf
|
||||||
|
|
||||||
ldr r0, .pm_mode
|
/*
|
||||||
cmp r0, #AT91_PM_STANDBY
|
* DDR Memory controller
|
||||||
beq standby
|
*/
|
||||||
cmp r0, #AT91_PM_BACKUP
|
|
||||||
beq backup_mode
|
|
||||||
|
|
||||||
bl at91_ulp_mode
|
/* LPDDR1 --> force DDR2 mode during self-refresh */
|
||||||
b exit_suspend
|
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]
|
||||||
|
|
||||||
standby:
|
/* Active DDRC self-refresh mode */
|
||||||
/* Wait for interrupt */
|
ldr r3, [r2, #AT91_DDRSDRC_LPR]
|
||||||
ldr pmc, .pmc_base
|
str r3, .saved_sam9_lpr
|
||||||
at91_cpu_idle
|
bic r3, r3, #AT91_DDRSDRC_LPCB
|
||||||
b exit_suspend
|
orr r3, r3, #AT91_DDRSDRC_LPCB_SELF_REFRESH
|
||||||
|
str r3, [r2, #AT91_DDRSDRC_LPR]
|
||||||
|
|
||||||
backup_mode:
|
/* If using the 2nd ddr controller */
|
||||||
bl at91_backup_mode
|
ldr r2, .sramc1_base
|
||||||
b exit_suspend
|
cmp r2, #0
|
||||||
|
beq sr_ena_no_2nd_ddrc
|
||||||
|
|
||||||
exit_suspend:
|
ldr r3, [r2, #AT91_DDRSDRC_MDR]
|
||||||
/* Exit the self-refresh mode */
|
str r3, .saved_sam9_mdr1
|
||||||
mov r0, #SRAMC_SELF_FRESH_EXIT
|
bic r3, r3, #~AT91_DDRSDRC_MD
|
||||||
bl at91_sramc_self_refresh
|
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]
|
||||||
|
|
||||||
/* Restore registers, and return */
|
/* Active DDRC self-refresh mode */
|
||||||
ldmfd sp!, {r4 - r12, pc}
|
ldr r3, [r2, #AT91_DDRSDRC_LPR]
|
||||||
ENDPROC(at91_pm_suspend_in_sram)
|
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]
|
||||||
|
|
||||||
ENTRY(at91_backup_mode)
|
sr_ena_no_2nd_ddrc:
|
||||||
/* Switch the master clock source to slow clock. */
|
b sr_ena_exit
|
||||||
ldr pmc, .pmc_base
|
|
||||||
ldr tmp2, .mckr_offset
|
|
||||||
ldr tmp1, [pmc, tmp2]
|
|
||||||
bic tmp1, tmp1, #AT91_PMC_CSS
|
|
||||||
str tmp1, [pmc, tmp2]
|
|
||||||
|
|
||||||
wait_mckrdy
|
/*
|
||||||
|
* 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]
|
||||||
|
|
||||||
/*BUMEN*/
|
ldr r3, .saved_sam9_lpr
|
||||||
ldr r0, .sfrbu
|
str r3, [r2, #AT91_SDRAMC_LPR]
|
||||||
mov tmp1, #0x1
|
|
||||||
str tmp1, [r0, #0x10]
|
|
||||||
|
|
||||||
/* Shutdown */
|
sr_ena_exit:
|
||||||
ldr r0, .shdwc
|
.endm
|
||||||
mov tmp1, #0xA5000000
|
|
||||||
add tmp1, tmp1, #0x1
|
/**
|
||||||
str tmp1, [r0, #0]
|
* Disable self-refresh
|
||||||
ENDPROC(at91_backup_mode)
|
*
|
||||||
|
* 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
|
||||||
|
|
||||||
.macro at91_pm_ulp0_mode
|
.macro at91_pm_ulp0_mode
|
||||||
ldr pmc, .pmc_base
|
ldr pmc, .pmc_base
|
||||||
|
@ -503,7 +552,7 @@ ENDPROC(at91_backup_mode)
|
||||||
2:
|
2:
|
||||||
.endm
|
.endm
|
||||||
|
|
||||||
ENTRY(at91_ulp_mode)
|
.macro at91_ulp_mode
|
||||||
ldr pmc, .pmc_base
|
ldr pmc, .pmc_base
|
||||||
ldr tmp2, .mckr_offset
|
ldr tmp2, .mckr_offset
|
||||||
ldr tmp3, .pm_mode
|
ldr tmp3, .pm_mode
|
||||||
|
@ -552,133 +601,97 @@ ulp_exit:
|
||||||
|
|
||||||
wait_mckrdy
|
wait_mckrdy
|
||||||
|
|
||||||
mov pc, lr
|
.endm
|
||||||
ENDPROC(at91_ulp_mode)
|
|
||||||
|
.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]
|
||||||
|
|
||||||
|
wait_mckrdy
|
||||||
|
|
||||||
|
/*BUMEN*/
|
||||||
|
ldr r0, .sfrbu
|
||||||
|
mov tmp1, #0x1
|
||||||
|
str tmp1, [r0, #0x10]
|
||||||
|
|
||||||
|
/* Shutdown */
|
||||||
|
ldr r0, .shdwc
|
||||||
|
mov tmp1, #0xA5000000
|
||||||
|
add tmp1, tmp1, #0x1
|
||||||
|
str tmp1, [r0, #0]
|
||||||
|
.endm
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* void at91_sramc_self_refresh(unsigned int is_active)
|
* void at91_suspend_sram_fn(struct at91_pm_data*)
|
||||||
*
|
|
||||||
* @input param:
|
* @input param:
|
||||||
* @r0: 1 - active self-refresh mode
|
* @r0: base address of struct at91_pm_data
|
||||||
* 0 - exit self-refresh mode
|
|
||||||
* register usage:
|
|
||||||
* @r1: memory type
|
|
||||||
* @r2: base address of the sram controller
|
|
||||||
*/
|
*/
|
||||||
|
/* 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}
|
||||||
|
|
||||||
ENTRY(at91_sramc_self_refresh)
|
/* Drain write buffer */
|
||||||
ldr r1, .memtype
|
mov tmp1, #0
|
||||||
ldr r2, .sramc_base
|
mcr p15, 0, tmp1, c7, c10, 4
|
||||||
|
|
||||||
cmp r1, #AT91_MEMCTRL_MC
|
ldr tmp1, [r0, #PM_DATA_PMC]
|
||||||
bne ddrc_sf
|
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]
|
||||||
|
|
||||||
/*
|
/* Active the self-refresh mode */
|
||||||
* at91rm9200 Memory controller
|
at91_sramc_self_refresh_ena
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
ldr r0, .pm_mode
|
||||||
* For exiting the self-refresh mode, do nothing,
|
cmp r0, #AT91_PM_STANDBY
|
||||||
* automatically exit the self-refresh mode.
|
beq standby
|
||||||
*/
|
cmp r0, #AT91_PM_BACKUP
|
||||||
tst r0, #SRAMC_SELF_FRESH_ACTIVE
|
beq backup_mode
|
||||||
beq exit_sramc_sf
|
|
||||||
|
|
||||||
/* Active SDRAM self-refresh mode */
|
at91_ulp_mode
|
||||||
mov r3, #1
|
b exit_suspend
|
||||||
str r3, [r2, #AT91_MC_SDRAMC_SRR]
|
|
||||||
b exit_sramc_sf
|
|
||||||
|
|
||||||
ddrc_sf:
|
standby:
|
||||||
cmp r1, #AT91_MEMCTRL_DDRSDR
|
/* Wait for interrupt */
|
||||||
bne sdramc_sf
|
ldr pmc, .pmc_base
|
||||||
|
at91_cpu_idle
|
||||||
|
b exit_suspend
|
||||||
|
|
||||||
/*
|
backup_mode:
|
||||||
* DDR Memory controller
|
at91_backup_mode
|
||||||
*/
|
|
||||||
tst r0, #SRAMC_SELF_FRESH_ACTIVE
|
|
||||||
beq ddrc_exit_sf
|
|
||||||
|
|
||||||
/* LPDDR1 --> force DDR2 mode during self-refresh */
|
exit_suspend:
|
||||||
ldr r3, [r2, #AT91_DDRSDRC_MDR]
|
/* Exit the self-refresh mode */
|
||||||
str r3, .saved_sam9_mdr
|
at91_sramc_self_refresh_dis
|
||||||
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]
|
|
||||||
|
|
||||||
/* Active DDRC self-refresh mode */
|
/* Restore registers, and return */
|
||||||
ldr r3, [r2, #AT91_DDRSDRC_LPR]
|
ldmfd sp!, {r4 - r12, pc}
|
||||||
str r3, .saved_sam9_lpr
|
ENDPROC(at91_pm_suspend_in_sram)
|
||||||
bic r3, r3, #AT91_DDRSDRC_LPCB
|
|
||||||
orr r3, r3, #AT91_DDRSDRC_LPCB_SELF_REFRESH
|
|
||||||
str r3, [r2, #AT91_DDRSDRC_LPR]
|
|
||||||
|
|
||||||
/* If using the 2nd ddr controller */
|
|
||||||
ldr r2, .sramc1_base
|
|
||||||
cmp r2, #0
|
|
||||||
beq no_2nd_ddrc
|
|
||||||
|
|
||||||
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]
|
|
||||||
|
|
||||||
/* 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]
|
|
||||||
|
|
||||||
no_2nd_ddrc:
|
|
||||||
b exit_sramc_sf
|
|
||||||
|
|
||||||
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]
|
|
||||||
|
|
||||||
/* 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 exit_sramc_sf
|
|
||||||
|
|
||||||
/*
|
|
||||||
* SDRAMC Memory controller
|
|
||||||
*/
|
|
||||||
sdramc_sf:
|
|
||||||
tst r0, #SRAMC_SELF_FRESH_ACTIVE
|
|
||||||
beq sdramc_exit_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]
|
|
||||||
|
|
||||||
sdramc_exit_sf:
|
|
||||||
ldr r3, .saved_sam9_lpr
|
|
||||||
str r3, [r2, #AT91_SDRAMC_LPR]
|
|
||||||
|
|
||||||
exit_sramc_sf:
|
|
||||||
mov pc, lr
|
|
||||||
ENDPROC(at91_sramc_self_refresh)
|
|
||||||
|
|
||||||
.pmc_base:
|
.pmc_base:
|
||||||
.word 0
|
.word 0
|
||||||
|
|
Loading…
Add table
Reference in a new issue