blob: e25b561285ce1d9408a8a099dabe37670dedc29b [file]
/*
* Copyright 2020, Data61, CSIRO (ABN 41 687 119 230)
*
* SPDX-License-Identifier: GPL-2.0-only
*/
#include <autoconf.h>
#include <elfloader/gen_config.h>
#include <devices_gen.h>
#include <drivers/smp.h>
#include <printf.h>
#include <cpuid.h>
#include <abort.h>
#include <elfloader.h>
#include <armv/smp.h>
#include <armv/machine.h>
#if CONFIG_MAX_NUM_NODES > 1
static volatile int non_boot_lock = 0;
void arm_disable_dcaches(void);
extern void const *dtb;
extern uint32_t dtb_size;
WEAK void non_boot_init(void) {}
/* Entry point for all CPUs other than the initial. */
void non_boot_main(void)
{
#ifndef CONFIG_ARCH_AARCH64
arm_disable_dcaches();
#endif
/* Spin until the first CPU has finished initialisation. */
while (!non_boot_lock) {
#ifndef CONFIG_ARCH_AARCH64
cpu_idle();
#endif
}
/* Initialise any platform-specific per-core state */
non_boot_init();
#ifndef CONFIG_ARM_HYPERVISOR_SUPPORT
if (is_hyp_mode()) {
extern void leave_hyp(void);
leave_hyp();
}
#endif
/* Enable the MMU, and enter the kernel. */
if (is_hyp_mode()) {
arm_enable_hyp_mmu();
} else {
arm_enable_mmu();
}
/* Jump to the kernel. */
((init_arm_kernel_t)kernel_info.virt_entry)(user_info.phys_region_start,
user_info.phys_region_end, user_info.phys_virt_offset,
user_info.virt_entry, (paddr_t)dtb, dtb_size);
printf("AP Kernel returned back to the elf-loader.\n");
abort();
}
/* TODO: convert imx7 to driver model and remove WEAK */
WEAK void init_cpus(void)
{
/*
* first, figure out which CPU we're booting on.
*/
int booting_cpu_index = -1;
word_t mpidr = read_cpuid_mpidr();
int i;
for (i = 0; elfloader_cpus[i].compat != NULL; i++) {
if (elfloader_cpus[i].cpu_id == mpidr) {
booting_cpu_index = i;
break;
}
}
if (booting_cpu_index == -1) {
printf("Could not find cpu entry for boot cpu (mpidr=0x%x)\n", mpidr);
abort();
}
printf("Boot cpu id = 0x%x, index=%d\n", mpidr, booting_cpu_index);
/*
* We want to boot CPUs in the same cluster before we boot CPUs in another cluster.
* This is important on systems like TX2, where the system boots on the A57 cluster,
* even though the Denver cluster is the "first" cluster according to the mpidr registers.
*
* There are a couple of assumptions made here:
* 1. The elfloader_cpus array is ordered based on the cpuid field (guaranteed by hardware_gen).
* 2. The CPU we boot on is the first CPU in a cluster (not necessarily the first cluster).
*/
int start_index = booting_cpu_index;
int num_cpus = 1;
for (i = start_index + 1; num_cpus < CONFIG_MAX_NUM_NODES && i != start_index; i++) {
if (i == booting_cpu_index) {
continue;
}
if (elfloader_cpus[i].compat == NULL) {
/* move back to start of the array if we started somewhere in the middle */
i = -1;
continue;
}
int ret = plat_cpu_on(&elfloader_cpus[i], core_entry, &core_stacks[num_cpus][0]);
if (ret != 0) {
printf("Failed to boot cpu 0x%x: %d\n", elfloader_cpus[i].cpu_id, ret);
abort();
}
while (!is_core_up(num_cpus));
printf("Core %d is up with logic id %d\n", elfloader_cpus[i].cpu_id, num_cpus);
num_cpus++;
}
#ifdef CONFIG_ARCH_AARCH64
/* main CPU has thread id == 0 */
MSR("tpidr_el1", 0);
#endif
}
void smp_boot(void)
{
#ifndef CONFIG_ARCH_AARCH64
arm_disable_dcaches();
#endif
init_cpus();
non_boot_lock = 1;
}
#endif /* CONFIG_MAX_NUM_NODES */