diff options
author | Akshay Saraswat <akshay.s@samsung.com> | 2015-02-20 13:27:12 +0530 |
---|---|---|
committer | Minkyu Kang <mk7.kang@samsung.com> | 2015-02-28 18:03:46 +0900 |
commit | ac0d98cd557e0939bd0f10ff68e2e648a74bbea6 (patch) | |
tree | ff8fee5d3b87261254d1fea5f3c4461b47f984f8 /arch/arm/cpu/armv7/exynos | |
parent | 1a8aae9b946d707d5dd2b1616e9c9c80c3daf178 (diff) | |
download | u-boot-imx-ac0d98cd557e0939bd0f10ff68e2e648a74bbea6.zip u-boot-imx-ac0d98cd557e0939bd0f10ff68e2e648a74bbea6.tar.gz u-boot-imx-ac0d98cd557e0939bd0f10ff68e2e648a74bbea6.tar.bz2 |
Exynos542x: CPU: Power down all secondary cores
This patch adds code to shutdown secondary cores.
When U-boot comes up, all secondary cores appear powered on,
which is undesirable and causes side effects while
initializing these cores in kernel.
Secondary core power down happens in following steps:
Step-1: After Exynos power-on, primary core starts executing first.
Step-2: In iROM code every core has to check 2 flags i.e.
addresses 0x02020028 & 0x02020004.
Step-3: Initially 0x02020028 is 0 for all cores and 0x02020004 has a
jump address for primary core and 0 for all secondary cores.
Step-4: Therefore, primary core follows normal iROM execution and jumps
to BL1 eventually, whereas all secondary cores enter WFE.
Step-5: When primary core comes into function secondary_cores_configure,
it puts pointer to function power_down_core into 0x02020004
and provides DSB and SEV for all cores so that they may come out
of WFE and jump to power_down_core function.
Step-6: And ultimately because of power_down_core all
secondary cores shut-down.
Signed-off-by: Kimoon Kim <kimoon.kim@samsung.com>
Signed-off-by: Akshay Saraswat <akshay.s@samsung.com>
Signed-off-by: Minkyu Kang <mk7.kang@samsung.com>
Diffstat (limited to 'arch/arm/cpu/armv7/exynos')
-rw-r--r-- | arch/arm/cpu/armv7/exynos/exynos5_setup.h | 3 | ||||
-rw-r--r-- | arch/arm/cpu/armv7/exynos/lowlevel_init.c | 69 |
2 files changed, 72 insertions, 0 deletions
diff --git a/arch/arm/cpu/armv7/exynos/exynos5_setup.h b/arch/arm/cpu/armv7/exynos/exynos5_setup.h index 2eea48a..9073f50 100644 --- a/arch/arm/cpu/armv7/exynos/exynos5_setup.h +++ b/arch/arm/cpu/armv7/exynos/exynos5_setup.h @@ -700,6 +700,9 @@ #define CLK_DIV_CPERI1_VAL NOT_AVAILABLE #else + +#define CPU_CONFIG_STATUS_OFFSET 0x80 +#define CPU_RST_FLAG_VAL 0xFCBA0D10 #define PAD_RETENTION_DRAM_COREBLK_VAL 0x10000000 /* APLL_CON1 */ diff --git a/arch/arm/cpu/armv7/exynos/lowlevel_init.c b/arch/arm/cpu/armv7/exynos/lowlevel_init.c index 83e1dcf..e36f2fa 100644 --- a/arch/arm/cpu/armv7/exynos/lowlevel_init.c +++ b/arch/arm/cpu/armv7/exynos/lowlevel_init.c @@ -31,7 +31,9 @@ #include <asm/arch/tzpc.h> #include <asm/arch/periph.h> #include <asm/arch/pinmux.h> +#include <asm/arch/system.h> #include "common_setup.h" +#include "exynos5_setup.h" /* These are the things we can do during low-level init */ enum { @@ -42,6 +44,68 @@ enum { DO_POWER = 1 << 4, }; +#ifdef CONFIG_EXYNOS5420 +/* + * Pointer to this function is stored in iRam which is used + * for jump and power down of a specific core. + */ +static void power_down_core(void) +{ + uint32_t tmp, core_id, core_config; + + /* Get the unique core id */ + /* + * Multiprocessor Affinity Register + * [11:8] Cluster ID + * [1:0] CPU ID + */ + mrc_mpafr(core_id); + tmp = core_id & 0x3; + core_id = (core_id >> 6) & ~3; + core_id |= tmp; + core_id &= 0x3f; + + /* Set the status of the core to low */ + core_config = (core_id * CPU_CONFIG_STATUS_OFFSET); + core_config += EXYNOS5420_CPU_CONFIG_BASE; + writel(0x0, core_config); + + /* Core enter WFI */ + wfi(); +} + +/* + * Configurations for secondary cores are inapt at this stage. + * Reconfigure secondary cores. Shutdown and change the status + * of all cores except the primary core. + */ +static void secondary_cores_configure(void) +{ + uint32_t core_id; + + /* Store jump address for power down of secondary cores */ + writel((uint32_t)&power_down_core, CONFIG_PHY_IRAM_BASE + 0x4); + + /* Need all core power down check */ + dsb(); + sev(); + + /* + * Power down all cores(secondary) while primary core must + * wait for all cores to go down. + */ + for (core_id = 1; core_id != CONFIG_CORE_COUNT; core_id++) { + while ((readl(EXYNOS5420_CPU_STATUS_BASE + + (core_id * CPU_CONFIG_STATUS_OFFSET)) + & 0xff) != 0x0) { + isb(); + sev(); + } + isb(); + } +} +#endif + int do_lowlevel_init(void) { uint32_t reset_status; @@ -49,6 +113,11 @@ int do_lowlevel_init(void) arch_cpu_init(); +#ifdef CONFIG_EXYNOS5420 + /* Reconfigure secondary cores */ + secondary_cores_configure(); +#endif + reset_status = get_reset_status(); switch (reset_status) { |