summaryrefslogtreecommitdiff
path: root/arch/arm/cpu/armv8/fsl-layerscape/mp.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/cpu/armv8/fsl-layerscape/mp.c')
-rw-r--r--arch/arm/cpu/armv8/fsl-layerscape/mp.c80
1 files changed, 57 insertions, 23 deletions
diff --git a/arch/arm/cpu/armv8/fsl-layerscape/mp.c b/arch/arm/cpu/armv8/fsl-layerscape/mp.c
index 1ea887b331..bd85351705 100644
--- a/arch/arm/cpu/armv8/fsl-layerscape/mp.c
+++ b/arch/arm/cpu/armv8/fsl-layerscape/mp.c
@@ -6,6 +6,7 @@
#include <common.h>
#include <cpu_func.h>
#include <image.h>
+#include <log.h>
#include <asm/cache.h>
#include <asm/io.h>
#include <asm/system.h>
@@ -14,17 +15,14 @@
#include <linux/delay.h>
#include "cpu.h"
#include <asm/arch-fsl-layerscape/soc.h>
+#include <efi_loader.h>
DECLARE_GLOBAL_DATA_PTR;
void *get_spin_tbl_addr(void)
{
- return &__spin_table;
-}
-
-phys_addr_t determine_mp_bootpg(void)
-{
- return (phys_addr_t)&secondary_boot_code;
+ /* the spin table is at the beginning */
+ return secondary_boot_code_start;
}
void update_os_arch_secondary_cores(uint8_t os_arch)
@@ -43,7 +41,7 @@ void update_os_arch_secondary_cores(uint8_t os_arch)
}
#ifdef CONFIG_FSL_LSCH3
-void wake_secondary_core_n(int cluster, int core, int cluster_cores)
+static void wake_secondary_core_n(int cluster, int core, int cluster_cores)
{
struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
struct ccsr_reset __iomem *rst = (void *)(CONFIG_SYS_FSL_RST_ADDR);
@@ -80,7 +78,11 @@ int fsl_layerscape_wake_seconday_cores(void)
#endif
u32 cores, cpu_up_mask = 1;
int i, timeout = 10;
- u64 *table = get_spin_tbl_addr();
+ u64 *table;
+#ifdef CONFIG_EFI_LOADER
+ u64 reloc_addr = U32_MAX;
+ efi_status_t ret;
+#endif
#ifdef COUNTER_FREQUENCY_REAL
/* update for secondary cores */
@@ -89,16 +91,49 @@ int fsl_layerscape_wake_seconday_cores(void)
(unsigned long)&__real_cntfrq + 8);
#endif
+#ifdef CONFIG_EFI_LOADER
+ /*
+ * EFI will reserve 64kb for its runtime services. This will probably
+ * overlap with our spin table code, which is why we have to relocate
+ * it.
+ * Keep this after the __real_cntfrq update, so we have it when we
+ * copy the complete section here.
+ */
+ ret = efi_allocate_pages(EFI_ALLOCATE_MAX_ADDRESS,
+ EFI_RESERVED_MEMORY_TYPE,
+ efi_size_in_pages(secondary_boot_code_size),
+ &reloc_addr);
+ if (ret == EFI_SUCCESS) {
+ debug("Relocating spin table from %llx to %llx (size %lx)\n",
+ (u64)secondary_boot_code_start, reloc_addr,
+ secondary_boot_code_size);
+ memcpy((void *)reloc_addr, secondary_boot_code_start,
+ secondary_boot_code_size);
+ flush_dcache_range(reloc_addr,
+ reloc_addr + secondary_boot_code_size);
+
+ /* set new entry point for secondary cores */
+ secondary_boot_addr += (void *)reloc_addr -
+ secondary_boot_code_start;
+ flush_dcache_range((unsigned long)&secondary_boot_addr,
+ (unsigned long)&secondary_boot_addr + 8);
+
+ /* this will be used to reserve the memory */
+ secondary_boot_code_start = (void *)reloc_addr;
+ }
+#endif
+
cores = cpu_mask();
/* Clear spin table so that secondary processors
* observe the correct value after waking up from wfe.
*/
+ table = get_spin_tbl_addr();
memset(table, 0, CONFIG_MAX_CPUS*SPIN_TABLE_ELEM_SIZE);
flush_dcache_range((unsigned long)table,
(unsigned long)table +
(CONFIG_MAX_CPUS*SPIN_TABLE_ELEM_SIZE));
- printf("Waking secondary cores to start from %lx\n", gd->relocaddr);
+ debug("Waking secondary cores to start from %lx\n", gd->relocaddr);
#ifdef CONFIG_FSL_LSCH3
gur_out32(&gur->bootlocptrh, (u32)(gd->relocaddr >> 32));
@@ -168,11 +203,11 @@ int fsl_layerscape_wake_seconday_cores(void)
udelay(10);
}
if (timeout <= 0) {
- printf("Not all cores (0x%x) are up (0x%x)\n",
- cores, cpu_up_mask);
+ printf("CPU: Failed to bring up some cores (mask 0x%x)\n",
+ cores ^ cpu_up_mask);
return 1;
}
- printf("All (%d) cores are up.\n", hweight32(cores));
+ printf("CPU: %d cores online\n", hweight32(cores));
return 0;
}
@@ -189,9 +224,9 @@ static int is_pos_valid(unsigned int pos)
int is_core_online(u64 cpu_id)
{
- u64 *table;
+ u64 *table = get_spin_tbl_addr();
int pos = id_to_core(cpu_id);
- table = (u64 *)get_spin_tbl_addr() + pos * WORDS_PER_SPIN_TABLE_ENTRY;
+ table += pos * WORDS_PER_SPIN_TABLE_ENTRY;
return table[SPIN_TABLE_ELEM_STATUS_IDX] == 1;
}
@@ -237,18 +272,16 @@ static int core_to_pos(int nr)
int cpu_status(u32 nr)
{
- u64 *table;
+ u64 *table = get_spin_tbl_addr();
int pos;
if (nr == 0) {
- table = (u64 *)get_spin_tbl_addr();
printf("table base @ 0x%p\n", table);
} else {
pos = core_to_pos(nr);
if (pos < 0)
return -1;
- table = (u64 *)get_spin_tbl_addr() + pos *
- WORDS_PER_SPIN_TABLE_ENTRY;
+ table += pos * WORDS_PER_SPIN_TABLE_ENTRY;
printf("table @ 0x%p\n", table);
printf(" addr - 0x%016llx\n",
table[SPIN_TABLE_ELEM_ENTRY_ADDR_IDX]);
@@ -264,7 +297,7 @@ int cpu_status(u32 nr)
int cpu_release(u32 nr, int argc, char *const argv[])
{
u64 boot_addr;
- u64 *table = (u64 *)get_spin_tbl_addr();
+ u64 *table = get_spin_tbl_addr();
int pos;
pos = core_to_pos(nr);
@@ -277,11 +310,12 @@ int cpu_release(u32 nr, int argc, char *const argv[])
flush_dcache_range((unsigned long)table,
(unsigned long)table + SPIN_TABLE_ELEM_SIZE);
asm volatile("dsb st");
- smp_kick_all_cpus(); /* only those with entry addr set will run */
+
/*
- * When the first release command runs, all cores are set to go. Those
- * without a valid entry address will be trapped by "wfe". "sev" kicks
- * them off to check the address again. When set, they continue to run.
+ * The secondary CPUs polling the spin-table above for a non-zero
+ * value. To save power "wfe" is called. Thus call "sev" here to
+ * wake the CPUs and let them check the spin-table again (see
+ * slave_cpu loop in lowlevel.S)
*/
asm volatile("sev");