
Hi Lukasz,
Hi Akshay,
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.
Could you provide exact names of those registers? I'm familiar with Samsung SoCs but I cannot recall which one those are.
As I have written in Step-2, these are addresses (SRAM) and not registers. Our iROM code has a part where it reads 0x02020028 for a specific vlaue FCBA0D10. If CPU finds that value then it extracts jump address from 0x02020004, else it follows normal boot path.
It would provide more readability to this commit message. Please fix it globally.
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
Changes since v2:
- No change.
Changes since v1:
- Removed unnecessary macros.
- Changed names of few macros for better understanding.
- Added MPIDR bit assignment info comment in power_down_core.
arch/arm/cpu/armv7/exynos/exynos5_setup.h | 3 ++ arch/arm/cpu/armv7/exynos/lowlevel_init.c | 69 ++++++++++++++++++++++++ arch/arm/include/asm/arch-exynos/cpu.h | 5 ++ arch/arm/include/asm/arch-exynos/system.h | 87 +++++++++++++++++++++++++++++++ 4 files changed, 164 insertions(+)
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) {
diff --git a/arch/arm/include/asm/arch-exynos/cpu.h b/arch/arm/include/asm/arch-exynos/cpu.h index 29674ad..e739520 100644 --- a/arch/arm/include/asm/arch-exynos/cpu.h +++ b/arch/arm/include/asm/arch-exynos/cpu.h @@ -153,6 +153,10 @@ #define EXYNOS5420_CLOCK_BASE 0x10010000 #define EXYNOS5420_POWER_BASE 0x10040000 #define EXYNOS5420_SWRESET 0x10040400 +#define EXYNOS5420_INFORM_BASE 0x10040800 +#define EXYNOS5420_SPARE_BASE 0x10040900 +#define EXYNOS5420_CPU_CONFIG_BASE 0x10042000 +#define EXYNOS5420_CPU_STATUS_BASE 0x10042004 #define EXYNOS5420_SYSREG_BASE 0x10050000 #define EXYNOS5420_TZPC_BASE 0x100E0000 #define EXYNOS5420_WATCHDOG_BASE 0x101D0000 @@ -186,6 +190,7 @@ #define EXYNOS5420_USB3PHY_BASE DEVICE_NOT_AVAILABLE #define EXYNOS5420_USB_HOST_XHCI_BASE DEVICE_NOT_AVAILABLE
#ifndef __ASSEMBLY__ #include <asm/io.h> /* CPU detection macros */ diff --git a/arch/arm/include/asm/arch-exynos/system.h b/arch/arm/include/asm/arch-exynos/system.h index 4968d3d..86903c3 100644 --- a/arch/arm/include/asm/arch-exynos/system.h +++ b/arch/arm/include/asm/arch-exynos/system.h @@ -37,6 +37,93 @@ struct exynos5_sysreg {
#define USB20_PHY_CFG_HOST_LINK_EN (1 << 0)
+#ifdef CONFIG_EXYNOS5420 +/*
- Data Synchronization Barrier acts as a special kind of memory
barrier.
- No instruction in program order after this instruction executes
until
- this instruction completes. This instruction completes when:
- All explicit memory accesses before this instruction complete.
- All Cache, Branch predictor and TLB maintenance operations
before
- this instruction complete.
- */
+#define dsb() __asm__ __volatile__ ("dsb\n\t" : : );
+/*
- This instruction causes an event to be signaled to all cores
- within a multiprocessor system. If SEV is implemented,
- WFE must also be implemented.
- */
+#define sev() __asm__ __volatile__ ("sev\n\t" : : ); +/*
- If the Event Register is not set, WFE suspends execution until
- one of the following events occurs:
- an IRQ interrupt, unless masked by the CPSR I-bit
- an FIQ interrupt, unless masked by the CPSR F-bit
- an Imprecise Data abort, unless masked by the CPSR A-bit
- a Debug Entry request, if Debug is enabled
- an Event signaled by another processor using the SEV
instruction.
- If the Event Register is set, WFE clears it and returns
immediately.
- If WFE is implemented, SEV must also be implemented.
- */
+#define wfe() __asm__ __volatile__ ("wfe\n\t" : : );
+/* Move 0xd3 value to CPSR register to enable SVC mode */ +#define svc32_mode_en() __asm__ __volatile__ \
("@ I&F disable, Mode: 0x13 -
SVC\n\t" \
"msr cpsr_c, #0x13|0xC0\n\t" : : )
+/* Set program counter with the given value */ +#define set_pc(x) __asm__ __volatile__ ("mov pc, %0\n\t" : : "r"(x)) + +/* Read Main Id register */ +#define mrc_midr(x) __asm__ __volatile__ \
("mrc p15, 0, %0, c0, c0, 0\n\t" :
"=r"(x) : ) + +/* Read Multiprocessor Affinity Register */ +#define mrc_mpafr(x) __asm__ __volatile__ \
("mrc p15, 0, %0, c0, c0, 5\n\t" :
"=r"(x) : ) + +/* Read System Control Register */ +#define mrc_sctlr(x) __asm__ __volatile__ \
("mrc p15, 0, %0, c1, c0, 0\n\t" :
"=r"(x) : ) + +/* Read Auxiliary Control Register */ +#define mrc_auxr(x) __asm__ __volatile__ \
("mrc p15, 0, %0, c1, c0, 1\n\t" :
"=r"(x) : ) + +/* Read L2 Control register */ +#define mrc_l2_ctlr(x) __asm__ __volatile__ \
("mrc p15, 1, %0, c9, c0, 2\n\t" :
"=r"(x) : ) + +/* Read L2 Auxilliary Control register */ +#define mrc_l2_aux_ctlr(x) __asm__ __volatile__ \
("mrc p15, 1, %0, c15, c0, 0\n\t" :
"=r"(x) : ) + +/* Write System Control Register */ +#define mcr_sctlr(x) __asm__ __volatile__ \
("mcr p15, 0, %0, c1, c0, 0\n\t" : :
"r"(x)) + +/* Write Auxiliary Control Register */ +#define mcr_auxr(x) __asm__ __volatile__ \
("mcr p15, 0, %0, c1, c0, 1\n\t" : :
"r"(x)) + +/* Invalidate all instruction caches to PoU */ +#define mcr_icache(x) __asm__ __volatile__ \
("mcr p15, 0, %0, c7, c5, 0\n\t" : :
"r"(x)) + +/* Invalidate unified TLB */ +#define mcr_tlb(x) __asm__ __volatile__ \
("mcr p15, 0, %0, c8, c7, 0\n\t" : :
"r"(x)) + +/* Write L2 Control register */ +#define mcr_l2_ctlr(x) __asm__ __volatile__ \
("mcr p15, 1, %0, c9, c0, 2\n\t" : :
"r"(x)) + +/* Write L2 Auxilliary Control register */ +#define mcr_l2_aux_ctlr(x) __asm__ __volatile__ \
("mcr p15, 1, %0, c15, c0, 0\n\t" : :
"r"(x)) +#endif
void set_usbhost_mode(unsigned int mode); void set_system_display_ctrl(void); int exynos_lcd_early_init(const void *blob);
-- Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
Regards, Akshay Saraswat