forked from Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1142 lines
23 KiB
1142 lines
23 KiB
/* SPDX-License-Identifier: GPL-2.0-only */ |
|
/* |
|
* arch/arm/mach-at91/pm_slow_clock.S |
|
* |
|
* Copyright (C) 2006 Savin Zlobec |
|
* |
|
* AT91SAM9 support: |
|
* Copyright (C) 2007 Anti Sullin <anti.sullin@artecdesign.ee> |
|
*/ |
|
#include <linux/linkage.h> |
|
#include <linux/clk/at91_pmc.h> |
|
#include "pm.h" |
|
#include "pm_data-offsets.h" |
|
|
|
#define SRAMC_SELF_FRESH_ACTIVE 0x01 |
|
#define SRAMC_SELF_FRESH_EXIT 0x00 |
|
|
|
pmc .req r0 |
|
tmp1 .req r4 |
|
tmp2 .req r5 |
|
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 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 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 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 r7, #AT91_PMC_PCK |
|
str r7, [pmc, #AT91_PMC_SCDR] |
|
|
|
dsb |
|
|
|
wfi @ Wait For Interrupt |
|
#else |
|
mcr p15, 0, tmp1, c7, c0, 4 |
|
#endif |
|
|
|
.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 |
|
* |
|
* 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 |
|
|
|
cmp r1, #AT91_MEMCTRL_MC |
|
bne sr_ena_ddrc_sf |
|
|
|
/* Active SDRAM self-refresh mode */ |
|
mov r3, #1 |
|
str r3, [r2, #AT91_MC_SDRAMC_SRR] |
|
b sr_ena_exit |
|
|
|
sr_ena_ddrc_sf: |
|
cmp r1, #AT91_MEMCTRL_DDRSDR |
|
bne sr_ena_sdramc_sf |
|
|
|
/* |
|
* DDR Memory controller |
|
*/ |
|
|
|
/* 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] |
|
|
|
/* 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] |
|
|
|
/* If using the 2nd ddr controller */ |
|
ldr r2, .sramc1_base |
|
cmp r2, #0 |
|
beq sr_ena_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] |
|
|
|
sr_ena_no_2nd_ddrc: |
|
b sr_ena_exit |
|
|
|
/* |
|
* 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 |
|
ldr tmp2, .pm_mode |
|
ldr tmp3, .mckr_offset |
|
|
|
/* Check if ULP0 fast variant has been requested. */ |
|
cmp tmp2, #AT91_PM_ULP0_FAST |
|
bne 0f |
|
|
|
/* Set highest prescaler for power saving */ |
|
ldr tmp1, [pmc, tmp3] |
|
bic tmp1, tmp1, #AT91_PMC_PRES |
|
orr tmp1, tmp1, #AT91_PMC_PRES_64 |
|
str tmp1, [pmc, tmp3] |
|
|
|
mov tmp3, #0 |
|
wait_mckrdy tmp3 |
|
b 1f |
|
|
|
0: |
|
/* Turn off the crystal oscillator */ |
|
ldr tmp1, [pmc, #AT91_CKGR_MOR] |
|
bic tmp1, tmp1, #AT91_PMC_MOSCEN |
|
orr tmp1, tmp1, #AT91_PMC_KEY |
|
str tmp1, [pmc, #AT91_CKGR_MOR] |
|
|
|
/* Save RC oscillator state */ |
|
ldr tmp1, [pmc, #AT91_PMC_SR] |
|
str tmp1, .saved_osc_status |
|
tst tmp1, #AT91_PMC_MOSCRCS |
|
bne 1f |
|
|
|
/* Turn off RC oscillator */ |
|
ldr tmp1, [pmc, #AT91_CKGR_MOR] |
|
bic tmp1, tmp1, #AT91_PMC_MOSCRCEN |
|
bic tmp1, tmp1, #AT91_PMC_KEY_MASK |
|
orr tmp1, tmp1, #AT91_PMC_KEY |
|
str tmp1, [pmc, #AT91_CKGR_MOR] |
|
|
|
/* Wait main RC disabled done */ |
|
2: ldr tmp1, [pmc, #AT91_PMC_SR] |
|
tst tmp1, #AT91_PMC_MOSCRCS |
|
bne 2b |
|
|
|
/* Wait for interrupt */ |
|
1: at91_cpu_idle |
|
|
|
/* Check if ULP0 fast variant has been requested. */ |
|
cmp tmp2, #AT91_PM_ULP0_FAST |
|
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] |
|
|
|
mov tmp3, #0 |
|
wait_mckrdy tmp3 |
|
b 6f |
|
|
|
5: /* Restore RC oscillator state */ |
|
ldr tmp1, .saved_osc_status |
|
tst tmp1, #AT91_PMC_MOSCRCS |
|
beq 4f |
|
|
|
/* Turn on RC oscillator */ |
|
ldr tmp1, [pmc, #AT91_CKGR_MOR] |
|
orr tmp1, tmp1, #AT91_PMC_MOSCRCEN |
|
bic tmp1, tmp1, #AT91_PMC_KEY_MASK |
|
orr tmp1, tmp1, #AT91_PMC_KEY |
|
str tmp1, [pmc, #AT91_CKGR_MOR] |
|
|
|
/* Wait main RC stabilization */ |
|
3: ldr tmp1, [pmc, #AT91_PMC_SR] |
|
tst tmp1, #AT91_PMC_MOSCRCS |
|
beq 3b |
|
|
|
/* Turn on the crystal oscillator */ |
|
4: ldr tmp1, [pmc, #AT91_CKGR_MOR] |
|
orr tmp1, tmp1, #AT91_PMC_MOSCEN |
|
orr tmp1, tmp1, #AT91_PMC_KEY |
|
str tmp1, [pmc, #AT91_CKGR_MOR] |
|
|
|
wait_moscrdy |
|
6: |
|
.endm |
|
|
|
/** |
|
* Note: This procedure only applies on the platform which uses |
|
* the external crystal oscillator as a main clock source. |
|
*/ |
|
.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] |
|
str tmp1, .saved_osc_status |
|
tst tmp1, #AT91_PMC_MOSCRCS |
|
bne 2f |
|
|
|
/* Enable RC oscillator */ |
|
ldr tmp1, [pmc, #AT91_CKGR_MOR] |
|
orr tmp1, tmp1, #AT91_PMC_MOSCRCEN |
|
bic tmp1, tmp1, #AT91_PMC_KEY_MASK |
|
orr tmp1, tmp1, #AT91_PMC_KEY |
|
str tmp1, [pmc, #AT91_CKGR_MOR] |
|
|
|
/* Wait main RC stabilization */ |
|
1: ldr tmp1, [pmc, #AT91_PMC_SR] |
|
tst tmp1, #AT91_PMC_MOSCRCS |
|
beq 1b |
|
|
|
/* Switch the main clock source to 12-MHz RC oscillator */ |
|
2: ldr tmp1, [pmc, #AT91_CKGR_MOR] |
|
bic tmp1, tmp1, #AT91_PMC_MOSCSEL |
|
bic tmp1, tmp1, #AT91_PMC_KEY_MASK |
|
orr tmp1, tmp1, #AT91_PMC_KEY |
|
str tmp1, [pmc, #AT91_CKGR_MOR] |
|
|
|
wait_moscsels |
|
|
|
/* Disable the crystal oscillator */ |
|
ldr tmp1, [pmc, #AT91_CKGR_MOR] |
|
bic tmp1, tmp1, #AT91_PMC_MOSCEN |
|
bic tmp1, tmp1, #AT91_PMC_KEY_MASK |
|
orr tmp1, tmp1, #AT91_PMC_KEY |
|
str tmp1, [pmc, #AT91_CKGR_MOR] |
|
|
|
/* Switch the master clock source to main clock */ |
|
ldr tmp1, [pmc, tmp2] |
|
bic tmp1, tmp1, #AT91_PMC_CSS |
|
orr tmp1, tmp1, #AT91_PMC_CSS_MAIN |
|
str tmp1, [pmc, tmp2] |
|
|
|
wait_mckrdy tmp3 |
|
|
|
/* Enter the ULP1 mode by set WAITMODE bit in CKGR_MOR */ |
|
ldr tmp1, [pmc, #AT91_CKGR_MOR] |
|
orr tmp1, tmp1, #AT91_PMC_WAITMODE |
|
bic tmp1, tmp1, #AT91_PMC_KEY_MASK |
|
orr tmp1, tmp1, #AT91_PMC_KEY |
|
str tmp1, [pmc, #AT91_CKGR_MOR] |
|
|
|
/* Quirk for SAM9X60's PMC */ |
|
nop |
|
nop |
|
|
|
wait_mckrdy tmp3 |
|
|
|
/* Enable the crystal oscillator */ |
|
ldr tmp1, [pmc, #AT91_CKGR_MOR] |
|
orr tmp1, tmp1, #AT91_PMC_MOSCEN |
|
bic tmp1, tmp1, #AT91_PMC_KEY_MASK |
|
orr tmp1, tmp1, #AT91_PMC_KEY |
|
str tmp1, [pmc, #AT91_CKGR_MOR] |
|
|
|
wait_moscrdy |
|
|
|
/* Switch the master clock source to slow clock */ |
|
ldr tmp1, [pmc, tmp2] |
|
bic tmp1, tmp1, #AT91_PMC_CSS |
|
str tmp1, [pmc, tmp2] |
|
|
|
wait_mckrdy tmp3 |
|
|
|
/* Switch main clock source to crystal oscillator */ |
|
ldr tmp1, [pmc, #AT91_CKGR_MOR] |
|
orr tmp1, tmp1, #AT91_PMC_MOSCSEL |
|
bic tmp1, tmp1, #AT91_PMC_KEY_MASK |
|
orr tmp1, tmp1, #AT91_PMC_KEY |
|
str tmp1, [pmc, #AT91_CKGR_MOR] |
|
|
|
wait_moscsels |
|
|
|
/* Switch the master clock source to main clock */ |
|
ldr tmp1, [pmc, tmp2] |
|
bic tmp1, tmp1, #AT91_PMC_CSS |
|
orr tmp1, tmp1, #AT91_PMC_CSS_MAIN |
|
str tmp1, [pmc, tmp2] |
|
|
|
wait_mckrdy tmp3 |
|
|
|
/* Restore RC oscillator state */ |
|
ldr tmp1, .saved_osc_status |
|
tst tmp1, #AT91_PMC_MOSCRCS |
|
bne 3f |
|
|
|
/* Disable RC oscillator */ |
|
ldr tmp1, [pmc, #AT91_CKGR_MOR] |
|
bic tmp1, tmp1, #AT91_PMC_MOSCRCEN |
|
bic tmp1, tmp1, #AT91_PMC_KEY_MASK |
|
orr tmp1, tmp1, #AT91_PMC_KEY |
|
str tmp1, [pmc, #AT91_CKGR_MOR] |
|
|
|
/* Wait RC oscillator disable done */ |
|
4: ldr tmp1, [pmc, #AT91_PMC_SR] |
|
tst tmp1, #AT91_PMC_MOSCRCS |
|
bne 4b |
|
|
|
3: |
|
.endm |
|
|
|
.macro at91_plla_disable |
|
/* Save PLLA setting and disable it */ |
|
ldr tmp1, .pmc_version |
|
cmp tmp1, #AT91_PMC_V1 |
|
beq 1f |
|
|
|
#ifdef CONFIG_HAVE_AT91_SAM9X60_PLL |
|
/* Save PLLA settings. */ |
|
ldr tmp2, [pmc, #AT91_PMC_PLL_UPDT] |
|
bic tmp2, tmp2, #AT91_PMC_PLL_UPDT_ID |
|
str tmp2, [pmc, #AT91_PMC_PLL_UPDT] |
|
|
|
/* save div. */ |
|
mov tmp1, #0 |
|
ldr tmp2, [pmc, #AT91_PMC_PLL_CTRL0] |
|
bic tmp2, tmp2, #0xffffff00 |
|
orr tmp1, tmp1, tmp2 |
|
|
|
/* save mul. */ |
|
ldr tmp2, [pmc, #AT91_PMC_PLL_CTRL1] |
|
bic tmp2, tmp2, #0xffffff |
|
orr tmp1, tmp1, tmp2 |
|
str tmp1, .saved_pllar |
|
|
|
/* step 2. */ |
|
ldr tmp1, [pmc, #AT91_PMC_PLL_UPDT] |
|
bic tmp1, tmp1, #AT91_PMC_PLL_UPDT_UPDATE |
|
bic tmp1, tmp1, #AT91_PMC_PLL_UPDT_ID |
|
str tmp1, [pmc, #AT91_PMC_PLL_UPDT] |
|
|
|
/* step 3. */ |
|
ldr tmp1, [pmc, #AT91_PMC_PLL_CTRL0] |
|
bic tmp1, tmp1, #AT91_PMC_PLL_CTRL0_ENPLLCK |
|
orr tmp1, tmp1, #AT91_PMC_PLL_CTRL0_ENPLL |
|
str tmp1, [pmc, #AT91_PMC_PLL_CTRL0] |
|
|
|
/* step 4. */ |
|
ldr tmp1, [pmc, #AT91_PMC_PLL_UPDT] |
|
orr tmp1, tmp1, #AT91_PMC_PLL_UPDT_UPDATE |
|
bic tmp1, tmp1, #AT91_PMC_PLL_UPDT_ID |
|
str tmp1, [pmc, #AT91_PMC_PLL_UPDT] |
|
|
|
/* step 5. */ |
|
ldr tmp1, [pmc, #AT91_PMC_PLL_CTRL0] |
|
bic tmp1, tmp1, #AT91_PMC_PLL_CTRL0_ENPLL |
|
str tmp1, [pmc, #AT91_PMC_PLL_CTRL0] |
|
|
|
/* step 7. */ |
|
ldr tmp1, [pmc, #AT91_PMC_PLL_UPDT] |
|
orr tmp1, tmp1, #AT91_PMC_PLL_UPDT_UPDATE |
|
bic tmp1, tmp1, #AT91_PMC_PLL_UPDT_ID |
|
str tmp1, [pmc, #AT91_PMC_PLL_UPDT] |
|
|
|
b 2f |
|
#endif |
|
|
|
1: /* Save PLLA setting and disable it */ |
|
ldr tmp1, [pmc, #AT91_CKGR_PLLAR] |
|
str tmp1, .saved_pllar |
|
|
|
/* Disable PLLA. */ |
|
mov tmp1, #AT91_PMC_PLLCOUNT |
|
orr tmp1, tmp1, #(1 << 29) /* bit 29 always set */ |
|
str tmp1, [pmc, #AT91_CKGR_PLLAR] |
|
2: |
|
.endm |
|
|
|
.macro at91_plla_enable |
|
ldr tmp2, .saved_pllar |
|
ldr tmp3, .pmc_version |
|
cmp tmp3, #AT91_PMC_V1 |
|
beq 4f |
|
|
|
#ifdef CONFIG_HAVE_AT91_SAM9X60_PLL |
|
/* step 1. */ |
|
ldr tmp1, [pmc, #AT91_PMC_PLL_UPDT] |
|
bic tmp1, tmp1, #AT91_PMC_PLL_UPDT_ID |
|
bic tmp1, tmp1, #AT91_PMC_PLL_UPDT_UPDATE |
|
str tmp1, [pmc, #AT91_PMC_PLL_UPDT] |
|
|
|
/* step 2. */ |
|
ldr tmp1, =AT91_PMC_PLL_ACR_DEFAULT_PLLA |
|
str tmp1, [pmc, #AT91_PMC_PLL_ACR] |
|
|
|
/* step 3. */ |
|
ldr tmp1, [pmc, #AT91_PMC_PLL_CTRL1] |
|
mov tmp3, tmp2 |
|
bic tmp3, tmp3, #0xffffff |
|
orr tmp1, tmp1, tmp3 |
|
str tmp1, [pmc, #AT91_PMC_PLL_CTRL1] |
|
|
|
/* step 8. */ |
|
ldr tmp1, [pmc, #AT91_PMC_PLL_UPDT] |
|
bic tmp1, tmp1, #AT91_PMC_PLL_UPDT_ID |
|
orr tmp1, tmp1, #AT91_PMC_PLL_UPDT_UPDATE |
|
str tmp1, [pmc, #AT91_PMC_PLL_UPDT] |
|
|
|
/* step 9. */ |
|
ldr tmp1, [pmc, #AT91_PMC_PLL_CTRL0] |
|
orr tmp1, tmp1, #AT91_PMC_PLL_CTRL0_ENLOCK |
|
orr tmp1, tmp1, #AT91_PMC_PLL_CTRL0_ENPLL |
|
orr tmp1, tmp1, #AT91_PMC_PLL_CTRL0_ENPLLCK |
|
bic tmp1, tmp1, #0xff |
|
mov tmp3, tmp2 |
|
bic tmp3, tmp3, #0xffffff00 |
|
orr tmp1, tmp1, tmp3 |
|
str tmp1, [pmc, #AT91_PMC_PLL_CTRL0] |
|
|
|
/* step 10. */ |
|
ldr tmp1, [pmc, #AT91_PMC_PLL_UPDT] |
|
orr tmp1, tmp1, #AT91_PMC_PLL_UPDT_UPDATE |
|
bic tmp1, tmp1, #AT91_PMC_PLL_UPDT_ID |
|
str tmp1, [pmc, #AT91_PMC_PLL_UPDT] |
|
|
|
/* step 11. */ |
|
3: ldr tmp1, [pmc, #AT91_PMC_PLL_ISR0] |
|
tst tmp1, #0x1 |
|
beq 3b |
|
b 2f |
|
#endif |
|
|
|
/* Restore PLLA setting */ |
|
4: str tmp2, [pmc, #AT91_CKGR_PLLAR] |
|
|
|
/* Enable PLLA. */ |
|
tst tmp2, #(AT91_PMC_MUL & 0xff0000) |
|
bne 1f |
|
tst tmp2, #(AT91_PMC_MUL & ~0xff0000) |
|
beq 2f |
|
|
|
1: ldr tmp1, [pmc, #AT91_PMC_SR] |
|
tst tmp1, #AT91_PMC_LOCKA |
|
beq 1b |
|
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 |
|
|
|
/* Save Master clock setting */ |
|
ldr tmp1, [pmc, tmp2] |
|
str tmp1, .saved_mckr |
|
|
|
/* |
|
* Set master clock source to: |
|
* - MAINCK if using ULP0 fast variant |
|
* - slow clock, otherwise |
|
*/ |
|
bic tmp1, tmp1, #AT91_PMC_CSS |
|
cmp tmp3, #AT91_PM_ULP0_FAST |
|
bne save_mck |
|
orr tmp1, tmp1, #AT91_PMC_CSS_MAIN |
|
save_mck: |
|
str tmp1, [pmc, tmp2] |
|
|
|
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 |
|
|
|
at91_pm_ulp0_mode |
|
b ulp_exit |
|
|
|
ulp1_mode: |
|
at91_pm_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 |
|
|
|
/* |
|
* Restore master clock setting |
|
*/ |
|
ldr tmp1, .mckr_offset |
|
ldr tmp2, .saved_mckr |
|
str tmp2, [pmc, tmp1] |
|
|
|
mov tmp3, #0 |
|
wait_mckrdy tmp3 |
|
|
|
at91_mckx_ps_restore |
|
.endm |
|
|
|
.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] |
|
|
|
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 |
|
|
|
/* |
|
* 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} |
|
|
|
/* Drain write buffer */ |
|
mov tmp1, #0 |
|
mcr p15, 0, tmp1, c7, c10, 4 |
|
|
|
/* Flush tlb. */ |
|
mov r4, #0 |
|
mcr p15, 0, r4, c8, c7, 0 |
|
|
|
ldr tmp1, [r0, #PM_DATA_PMC_MCKR_OFFSET] |
|
str tmp1, .mckr_offset |
|
ldr tmp1, [r0, #PM_DATA_PMC_VERSION] |
|
str tmp1, .pmc_version |
|
ldr tmp1, [r0, #PM_DATA_MEMCTRL] |
|
str tmp1, .memtype |
|
ldr tmp1, [r0, #PM_DATA_MODE] |
|
str tmp1, .pm_mode |
|
|
|
/* |
|
* ldrne below are here to preload their address in the TLB as access |
|
* to RAM may be limited while in self-refresh. |
|
*/ |
|
ldr tmp1, [r0, #PM_DATA_PMC] |
|
str tmp1, .pmc_base |
|
cmp tmp1, #0 |
|
ldrne tmp2, [tmp1, #0] |
|
|
|
ldr tmp1, [r0, #PM_DATA_RAMC0] |
|
str tmp1, .sramc_base |
|
cmp tmp1, #0 |
|
ldrne tmp2, [tmp1, #0] |
|
|
|
ldr tmp1, [r0, #PM_DATA_RAMC1] |
|
str tmp1, .sramc1_base |
|
cmp tmp1, #0 |
|
ldrne tmp2, [tmp1, #0] |
|
|
|
#ifndef CONFIG_SOC_SAM_V4_V5 |
|
/* ldrne below are here to preload their address in the TLB */ |
|
ldr tmp1, [r0, #PM_DATA_RAMC_PHY] |
|
str tmp1, .sramc_phy_base |
|
cmp tmp1, #0 |
|
ldrne tmp2, [tmp1, #0] |
|
|
|
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] |
|
#endif |
|
|
|
/* Active the self-refresh mode */ |
|
at91_sramc_self_refresh_ena |
|
|
|
ldr r0, .pm_mode |
|
cmp r0, #AT91_PM_STANDBY |
|
beq standby |
|
cmp r0, #AT91_PM_BACKUP |
|
beq backup_mode |
|
|
|
at91_ulp_mode |
|
b exit_suspend |
|
|
|
standby: |
|
/* Wait for interrupt */ |
|
ldr pmc, .pmc_base |
|
at91_cpu_idle |
|
b exit_suspend |
|
|
|
backup_mode: |
|
at91_backup_mode |
|
|
|
exit_suspend: |
|
/* Exit the self-refresh mode */ |
|
at91_sramc_self_refresh_dis |
|
|
|
/* Restore registers, and return */ |
|
ldmfd sp!, {r4 - r12, pc} |
|
ENDPROC(at91_pm_suspend_in_sram) |
|
|
|
.pmc_base: |
|
.word 0 |
|
.sramc_base: |
|
.word 0 |
|
.sramc1_base: |
|
.word 0 |
|
.sramc_phy_base: |
|
.word 0 |
|
.shdwc: |
|
.word 0 |
|
.sfrbu: |
|
.word 0 |
|
.memtype: |
|
.word 0 |
|
.pm_mode: |
|
.word 0 |
|
.mckr_offset: |
|
.word 0 |
|
.pmc_version: |
|
.word 0 |
|
.saved_mckr: |
|
.word 0 |
|
.saved_pllar: |
|
.word 0 |
|
.saved_sam9_lpr: |
|
.word 0 |
|
.saved_sam9_lpr1: |
|
.word 0 |
|
.saved_sam9_mdr: |
|
.word 0 |
|
.saved_sam9_mdr1: |
|
.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
|
|
|