arm64: implement CPU power down sequence as per A57/A53/A72 TRM

Implement the individual core powerdown sequence as per
Cortex-A57/A53/A72 TRM.

Based-on-the-work-by:
Varun Wadekar <vwadekar@nvidia.com>

BRANCH=none
BUG=none
TEST=boot on smaug/foster, verify the cpu_on/off is ok as well

Change-Id: I4719fcbe86b35f9b448d274e1732da5fc75346b0
Signed-off-by: Patrick Georgi <pgeorgi@chromium.org>
Original-Commit-Id: b6bdcc12150820dfad28cef3af3d8220847c5d74
Original-Change-Id: I65abab8cda55cfe7a0c424f3175677ed5e3c2a1c
Original-Signed-off-by: Joseph Lo <josephl@nvidia.com>
Original-Reviewed-on: https://chromium-review.googlesource.com/265827
Original-Reviewed-by: Aaron Durbin <adurbin@chromium.org>
Reviewed-on: http://review.coreboot.org/9980
Tested-by: build bot (Jenkins)
Reviewed-by: Marc Jones <marc.jones@se-eng.com>
This commit is contained in:
Joseph Lo 2015-04-15 10:09:50 +08:00 committed by Patrick Georgi
parent c4301f7969
commit c38d3e8131
5 changed files with 126 additions and 0 deletions

View File

@ -18,8 +18,14 @@
*/
void arm64_cpu_early_setup(void);
void cortex_a57_cpu_power_down(int l2_flush);
void __attribute__((weak)) arm64_cpu_early_setup(void)
{
/* Default empty implementation */
}
void __attribute__((weak)) cortex_a57_cpu_power_down(int l2_flush)
{
/* Default empty implementation */
}

View File

@ -21,3 +21,8 @@ config ARCH_ARM64_CPU_CORTEX_A57
bool
default n
depends on ARCH_ARM64
config ARCH_ARM64_CORTEX_A57_POWER_DOWN_SUPPORT
bool
default n
depends on ARCH_ARM64 && ARCH_ARM64_CPU_CORTEX_A57

View File

@ -18,6 +18,7 @@
*/
#include <arch/asm.h>
#include <arch/cache_helpers.h>
#include "cortex_a57.h"
ENTRY(arm64_cpu_early_setup)
@ -27,3 +28,97 @@ ENTRY(arm64_cpu_early_setup)
isb
ret
ENDPROC(arm64_cpu_early_setup)
/*
* CPU power down sequence as per A57/A53/A72 TRM
*
* x0 - L2 flush by HW(0) or SW(1), if system/HW driven L2 flush is supported
*
*/
#if IS_ENABLED(CONFIG_ARCH_ARM64_CORTEX_A57_POWER_DOWN_SUPPORT)
ENTRY(cortex_a57_cpu_power_down)
/* Store L2 cache flush request */
mov x13, x0
/* 1. Stop allocations to our data cache */
mrs x0, sctlr_el1
bic x0, x0, #1 << 2 // clear SCTLR.C
msr sctlr_el1, x0
isb
mrs x0, sctlr_el3
bic x0, x0, #1 << 2 // clear SCTLR.C
msr sctlr_el3, x0
isb
mrs x0, midr_el1
ubfx x0, x0, #4, #12
cmp x0, #CORTEX_A53_PN
b.eq a53
/* 2. Disable L2 prefetch */
mrs x0, CPUECTLR_EL1 // CPUECTLR_EL1
/* CPUECTLR[38], disable table walk descriptor access L2 prefetch */
orr x0, x0, #1 << 38
/*
* CPUECTLR[36:35] L2 instruction fetch prefetch distance
* 0 => disable instruction prefetch
*/
bic x0, x0, #3 << 35
/*
* CPUECTLR[33:32] L2 load/store prefetch distance
* 0 => disable instruction prefetch
*/
bic x0, x0, #3 << 32
msr CPUECTLR_EL1, x0
/* 3. ISB to ensure ectlr write is complete */
isb
/* 4. DSB to ensure prior prefetches are complete */
dsb sy
a53:
/* 5. Clean and invalidate L1 and L2 if X13 == 1 */
mov x0, #DCCISW
cmp x13, #1
bne 1f
bl flush_dcache_all
b 2f
1:
bl flush_dcache_louis
2:
/* 6. Leave coherency, clear SMPEN */
mrs x0, CPUECTLR_EL1
bic x0, x0, #(1 << SMPEN_SHIFT)
msr CPUECTLR_EL1, x0
/* 7. Set the DBGOSDLR.DLK, Double lock control bit */
mrs x0, osdlr_el1
orr x0, x0, #OSDLR_DBL_LOCK_BIT
msr osdlr_el1, x0
/*
* 9. Execute an ISB instruction to ensure that all of the
* System register changes from the previous steps have
* been committed.
*/
isb
/*
* 10. Execute a DSB instruction to ensure that all
* instruction cache, TLB, and branch predictor
* maintenance operations issued by any processor in the
* multiprocessor before the SMPEN bit was cleared have
* completed.
*/
dsb sy
/* 11. wfi */
3: wfi
/* we never return here */
b 3b
ENDPROC(cortex_a57_cpu_power_down)
#endif

View File

@ -23,4 +23,10 @@
#define CPUECTLR_EL1 S3_1_c15_c2_1
#define SMPEN_SHIFT 6
/* Cortex MIDR[15:4] PN */
#define CORTEX_A53_PN 0xd03
/* Double lock control bit */
#define OSDLR_DBL_LOCK_BIT 1
#endif /* __ARCH_ARM64_CORTEX_A57_H__ */

View File

@ -187,4 +187,18 @@ void arm64_cpu_startup_resume(void);
*/
void arm64_arch_timer_init(void);
/*
* The cortex_a57_cpu_power_down sequence as per A57/A53/A72 TRM.
* L2 flush by HW(0) or SW(1), if system/HW driven L2 flush is supported.
*/
#define NO_L2_FLUSH 0
#define L2_FLUSH_HW 0
#define L2_FLUSH_SW 1
#if IS_ENABLED(CONFIG_ARCH_ARM64_CORTEX_A57_POWER_DOWN_SUPPORT)
void cortex_a57_cpu_power_down(int l2_flush);
#else
static inline void cortex_a57_cpu_power_down(int l2_flush) {}
#endif
#endif /* __ARCH_CPU_H__ */