soc/cavium: Add secondary CPU support
Change-Id: I07428161615bcd3d03a3eea0df2dd813e08c8f66 Signed-off-by: Patrick Rudolph <patrick.rudolph@9elements.com> Reviewed-on: https://review.coreboot.org/25752 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: David Hendricks <david.hendricks@gmail.com>
This commit is contained in:
parent
ae15fec0b8
commit
88f81af1ef
|
@ -54,6 +54,9 @@ config FMDFILE
|
|||
string
|
||||
default "src/mainboard/$(CONFIG_MAINBOARD_DIR)/board.fmd"
|
||||
|
||||
config MAX_CPUS
|
||||
default 4
|
||||
|
||||
##########################################################
|
||||
#### Update below when adding a new derivative board. ####
|
||||
##########################################################
|
||||
|
|
|
@ -71,7 +71,7 @@ static void mainboard_print_info(void)
|
|||
thunderx_get_core_clock() / 1000000ULL);
|
||||
|
||||
printk(BIOS_INFO, "MB: #CPU cores : %zu\n",
|
||||
cpu_get_num_cores());
|
||||
cpu_get_num_available_cores());
|
||||
|
||||
printk(BIOS_INFO, "MB: RAM : %zu MiB\n",
|
||||
sdram_size_mb());
|
||||
|
@ -91,6 +91,10 @@ static void mainboard_init(struct device *dev)
|
|||
|
||||
/* Init timer */
|
||||
soc_timer_init();
|
||||
|
||||
/* Init CPUs */
|
||||
for (i = 1; i < CONFIG_MAX_CPUS; i++)
|
||||
start_cpu(i, NULL);
|
||||
}
|
||||
|
||||
static void mainboard_enable(struct device *dev)
|
||||
|
|
|
@ -62,6 +62,7 @@ ramstage-$(CONFIG_DRIVERS_UART) += uart.c
|
|||
ramstage-y += sdram.c
|
||||
ramstage-y += soc.c
|
||||
ramstage-y += cpu.c
|
||||
ramstage-y += cpu_secondary.S
|
||||
|
||||
# BDK coreboot interface
|
||||
ramstage-y += ../common/bdk-coreboot.c
|
||||
|
|
|
@ -14,13 +14,122 @@
|
|||
*/
|
||||
|
||||
#include <types.h>
|
||||
#include <soc/addressmap.h>
|
||||
#include <arch/io.h>
|
||||
#include <soc/cpu.h>
|
||||
#include <bdk-coreboot.h>
|
||||
#include <console/console.h>
|
||||
#include <timer.h>
|
||||
#include <delay.h>
|
||||
|
||||
/* Return the number of cores available in the chip */
|
||||
size_t cpu_get_num_cores(void)
|
||||
uint64_t cpu_get_available_core_mask(void)
|
||||
{
|
||||
uint64_t available = read64((void *)0x87e006001738ll);
|
||||
return bdk_dpop(available);
|
||||
return read64((void *)RST_PP_AVAILABLE);
|
||||
}
|
||||
|
||||
size_t cpu_get_num_available_cores(void)
|
||||
{
|
||||
return bdk_dpop(cpu_get_available_core_mask());
|
||||
}
|
||||
|
||||
static void (*secondary_c_entry)(size_t core_id);
|
||||
static size_t secondary_booted;
|
||||
|
||||
void secondary_cpu_init(size_t core_id)
|
||||
{
|
||||
write64(&secondary_booted, 1);
|
||||
dmb();
|
||||
|
||||
if (secondary_c_entry)
|
||||
secondary_c_entry(core_id);
|
||||
else
|
||||
asm("wfi");
|
||||
}
|
||||
|
||||
size_t cpu_self_get_core_id(void)
|
||||
{
|
||||
u32 mpidr_el1;
|
||||
asm("mrs %0, MPIDR_EL1\n\t" : "=r" (mpidr_el1) :: "memory");
|
||||
|
||||
/* Core is 4 bits from AFF0 and rest from AFF1 */
|
||||
size_t core_num;
|
||||
core_num = mpidr_el1 & 0xf;
|
||||
core_num |= (mpidr_el1 & 0xff00) >> 4;
|
||||
|
||||
return core_num;
|
||||
}
|
||||
|
||||
uint64_t cpu_self_get_core_mask(void)
|
||||
{
|
||||
return 1ULL << cpu_self_get_core_id();
|
||||
}
|
||||
|
||||
size_t start_cpu(size_t cpu, void (*entry_64)(size_t core_id))
|
||||
{
|
||||
const uint64_t coremask = 1ULL << cpu;
|
||||
struct stopwatch sw;
|
||||
uint64_t pending;
|
||||
|
||||
printk(BIOS_DEBUG, "CPU: Starting CPU%zu @ %p.\n", cpu, entry_64);
|
||||
|
||||
/* Core not available */
|
||||
if (!(coremask & cpu_get_available_core_mask()))
|
||||
return 1;
|
||||
|
||||
/* Only secondary CPUs are supported */
|
||||
if (cpu == cpu_self_get_core_id())
|
||||
return 1;
|
||||
|
||||
/* Check stack here, instead of in cpu_secondary.S */
|
||||
if ((CONFIG_STACK_SIZE * cpu) > _stack_sec_size)
|
||||
return 1;
|
||||
|
||||
/* Write the address of the main entry point */
|
||||
write64((void *)MIO_BOOT_AP_JUMP, (uintptr_t)secondary_init);
|
||||
|
||||
/* Get coremask of cores in reset */
|
||||
const uint64_t reset = read64((void *)RST_PP_RESET);
|
||||
printk(BIOS_INFO, "CPU: Cores currently in reset: 0x%llx\n", reset);
|
||||
|
||||
/* Setup entry for secondary core */
|
||||
write64(&secondary_c_entry, (uintptr_t)entry_64);
|
||||
write64(&secondary_booted, 0);
|
||||
dmb();
|
||||
|
||||
printk(BIOS_DEBUG, "CPU: Taking core %zu out of reset.\n", cpu);
|
||||
|
||||
/* Release core from reset */
|
||||
write64((void *)RST_PP_RESET, reset & ~coremask);
|
||||
|
||||
/* Wait for cores to finish coming out of reset */
|
||||
udelay(1);
|
||||
|
||||
stopwatch_init_usecs_expire(&sw, 1000000);
|
||||
do {
|
||||
pending = read64((void *)RST_PP_PENDING);
|
||||
} while (!stopwatch_expired(&sw) && (pending & coremask));
|
||||
|
||||
if (stopwatch_expired(&sw)) {
|
||||
printk(BIOS_ERR, "ERROR: Timeout waiting for reset "
|
||||
"pending to clear.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
stopwatch_init_usecs_expire(&sw, 1000000);
|
||||
|
||||
printk(BIOS_DEBUG, "CPU: Wait up to 1s for the core to boot...\n");
|
||||
while (!stopwatch_expired(&sw) && !read64(&secondary_booted))
|
||||
;
|
||||
|
||||
/* Cleanup */
|
||||
write64(&secondary_c_entry, 0);
|
||||
dmb();
|
||||
|
||||
if (!read64(&secondary_booted)) {
|
||||
printk(BIOS_ERR, "ERROR: Core %zu failed to start.\n", cpu);
|
||||
return 1;
|
||||
}
|
||||
|
||||
printk(BIOS_INFO, "CPU: Core %zu booted\n", cpu);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
* Early initialization code for aarch64 (a.k.a. armv8)
|
||||
*
|
||||
* Copyright 2016 Cavium, Inc. <support@cavium.com>
|
||||
* Copyright 2018-present Facebook, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; version 2 of
|
||||
* the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <arch/asm.h>
|
||||
#include <soc/addressmap.h>
|
||||
|
||||
// based on arm64_init_cpu
|
||||
ENTRY(secondary_init)
|
||||
/* Initialize PSTATE (unmask all exceptions, select SP_EL0). */
|
||||
msr SPSel, #0
|
||||
msr DAIFClr, #0xf
|
||||
|
||||
/* TODO: This is where we'd put non-boot CPUs into WFI if needed. */
|
||||
|
||||
/* x22: SCTLR, return address: x23 (callee-saved by subroutine) */
|
||||
mov x23, x30
|
||||
/* TODO: Assert that we always start running at EL3 */
|
||||
mrs x22, sctlr_el3
|
||||
|
||||
/* Activate ICache (12) already for speed during cache flush below. */
|
||||
orr x22, x22, #(1 << 12)
|
||||
msr sctlr_el3, x22
|
||||
isb
|
||||
|
||||
/* Invalidate dcache */
|
||||
bl dcache_invalidate_all
|
||||
|
||||
/* Deactivate MMU (0), Alignment Check (1) and DCache (2) */
|
||||
and x22, x22, # ~(1 << 0) & ~(1 << 1) & ~(1 << 2)
|
||||
/* Activate Stack Alignment (3) because why not */
|
||||
orr x22, x22, #(1 << 3)
|
||||
/* Set to little-endian (25) */
|
||||
and x22, x22, # ~(1 << 25)
|
||||
/* Deactivate write-xor-execute enforcement (19) */
|
||||
and x22, x22, # ~(1 << 19)
|
||||
msr sctlr_el3, x22
|
||||
|
||||
/* Invalidate icache and TLB for good measure */
|
||||
ic iallu
|
||||
tlbi alle3
|
||||
dsb sy
|
||||
isb
|
||||
|
||||
/* Load core ID to x0 */
|
||||
mrs x0, MPIDR_EL1
|
||||
and x1, x0, # 0xf
|
||||
lsr x0, x0, 4
|
||||
and x0, x0, # 0xff0
|
||||
orr x0, x0, x1
|
||||
|
||||
/* Each core gets CONFIG_STACK_SIZE bytes of stack */
|
||||
mov x2, # CONFIG_STACK_SIZE
|
||||
mul x1, x0, x2
|
||||
/* Backup core id */
|
||||
mov x22, x0
|
||||
ldr x0, =_stack_sec
|
||||
add x0, x1, x0 // x0 = CONFIG_STACK_SIZE * coreid + _stack_sec
|
||||
add x1, x0, # CONFIG_STACK_SIZE // x1 = x0 + CONFIG_STACK_SIZE
|
||||
|
||||
/* Initialize stack with sentinel value to later check overflow. */
|
||||
ldr x2, =0xdeadbeefdeadbeef
|
||||
|
||||
1:
|
||||
stp x2, x2, [x0], #16
|
||||
cmp x0, x1
|
||||
bne 1b
|
||||
|
||||
/* Leave a line of beef dead for easier visibility in stack dumps. */
|
||||
sub sp, x0, #16
|
||||
|
||||
/* Set arg0 to core id */
|
||||
mov x0, x22
|
||||
|
||||
/* Call C entry */
|
||||
bl secondary_cpu_init
|
||||
|
||||
ENDPROC(secondary_init)
|
|
@ -58,9 +58,14 @@
|
|||
|
||||
/* RST */
|
||||
#define RST_PF_BAR0 (0x87E006000000ULL + 0x1600)
|
||||
#define RST_PP_AVAILABLE (RST_PF_BAR0 + 0x138ULL)
|
||||
#define RST_PP_RESET (RST_PF_BAR0 + 0x140ULL)
|
||||
#define RST_PP_PENDING (RST_PF_BAR0 + 0x148ULL)
|
||||
|
||||
#define FUSF_PF_BAR0 0x87E004000000ULL
|
||||
#define MIO_FUS_PF_BAR0 0x87E003000000ULL
|
||||
#define MIO_BOOT_PF_BAR0 0x87E000000000ULL
|
||||
#define MIO_BOOT_AP_JUMP (MIO_BOOT_PF_BAR0 + 0xD0ULL)
|
||||
|
||||
/* PTP */
|
||||
#define MIO_PTP_PF_BAR0 0x807000000000ULL
|
||||
|
|
|
@ -17,6 +17,59 @@
|
|||
#ifndef __SOC_CAVIUM_CN81XX_CPU_H__
|
||||
#define __SOC_CAVIUM_CN81XX_CPU_H__
|
||||
|
||||
size_t cpu_get_num_cores(void);
|
||||
/**
|
||||
* Number of the Core on which the program is currently running.
|
||||
*
|
||||
* @return Number of cores
|
||||
*/
|
||||
size_t cpu_self_get_core_id(void);
|
||||
|
||||
/**
|
||||
* Return a mask representing this core in a 64bit bitmask
|
||||
*
|
||||
* @return The mask of active core.
|
||||
*/
|
||||
uint64_t cpu_self_get_core_mask(void);
|
||||
|
||||
/**
|
||||
* Return the mask of available cores.
|
||||
*
|
||||
* @return Mask of available cores
|
||||
*/
|
||||
uint64_t cpu_get_available_core_mask(void);
|
||||
|
||||
/**
|
||||
* Return the number of cores available in the chip.
|
||||
*
|
||||
* @return The number of available cores.
|
||||
*/
|
||||
size_t cpu_get_num_available_cores(void);
|
||||
|
||||
/**
|
||||
* Init secondary core and call the provided entry for given core.
|
||||
* A stack of size CONFIG_STACK_SIZE is set up for each core in REGION
|
||||
* stack_sec. The unique core id is passed to the entry point functions.
|
||||
*
|
||||
* @return zero on success
|
||||
*/
|
||||
size_t start_cpu(size_t cpu, void (*entry_64)(size_t core_id));
|
||||
|
||||
/**
|
||||
* Secondary ASM CPU entry point.
|
||||
* For internal use only.
|
||||
*/
|
||||
void secondary_init(void);
|
||||
|
||||
/**
|
||||
* Secondary CPU C entry point.
|
||||
* For internal use only.
|
||||
*/
|
||||
void secondary_cpu_init(size_t core_id);
|
||||
|
||||
/* Symbols in memlayout.ld */
|
||||
|
||||
extern u8 _stack_sec[];
|
||||
extern u8 _estack_sec[];
|
||||
#define _stack_sec_size (_estack_sec - _stack_sec)
|
||||
|
||||
#endif /* __SOC_CAVIUM_CN81XX_CPU_H__ */
|
||||
|
|
|
@ -35,6 +35,9 @@ SECTIONS
|
|||
SRAM_END(BOOTROM_OFFSET + 0x80000)
|
||||
TTB(BOOTROM_OFFSET + 0x80000, 512K)
|
||||
RAMSTAGE(BOOTROM_OFFSET + 0x100000, 512K)
|
||||
/* Stack for secondary CPUs */
|
||||
REGION(stack_sec, BOOTROM_OFFSET + 0x180000,
|
||||
CONFIG_MAX_CPUS * CONFIG_STACK_SIZE, 0x1000)
|
||||
|
||||
/* Leave some space for the payload */
|
||||
POSTRAM_CBFS_CACHE(0x2000000, 16M)
|
||||
|
|
|
@ -50,8 +50,11 @@ static void soc_final(device_t dev)
|
|||
|
||||
static struct device_operations soc_ops = {
|
||||
.read_resources = soc_read_resources,
|
||||
.set_resources = DEVICE_NOOP,
|
||||
.enable_resources = DEVICE_NOOP,
|
||||
.init = soc_init,
|
||||
.final = soc_final,
|
||||
.scan_bus = NULL,
|
||||
};
|
||||
|
||||
static void enable_soc_dev(device_t dev)
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
|
||||
ifeq ($(CONFIG_SOC_CAVIUM_COMMON),y)
|
||||
|
||||
CFLAGS_arm64 += -Wstack-usage=8192
|
||||
CFLAGS_arm64 += -Wstack-usage=$(CONFIG_STACK_SIZE)
|
||||
|
||||
bootblock-$(CONFIG_BOOTBLOCK_CUSTOM) += bootblock.c
|
||||
|
||||
|
|
Loading…
Reference in New Issue