Secondary cores need to be released from holdoff by boot release registers. With GPP bootrom, they can boot from main memory directly. Individual spin table is used for each core. Spin table and the boot page is reserved in device tree so OS won't overwrite. Signed-off-by: York Sun <yorksun@freescale.com> Signed-off-by: Arnab Basu <arnab.basu@freescale.com>master
parent
f43b4356a7
commit
40f8dec54d
@ -0,0 +1,58 @@ |
||||
/*
|
||||
* Copyright 2014 Freescale Semiconductor, Inc. |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
*/ |
||||
|
||||
#include <common.h> |
||||
#include <libfdt.h> |
||||
#include <fdt_support.h> |
||||
#include "mp.h" |
||||
|
||||
#ifdef CONFIG_MP |
||||
void ft_fixup_cpu(void *blob) |
||||
{ |
||||
int off; |
||||
__maybe_unused u64 spin_tbl_addr = (u64)get_spin_tbl_addr(); |
||||
fdt32_t *reg; |
||||
int addr_cells; |
||||
u64 val; |
||||
size_t *boot_code_size = &(__secondary_boot_code_size); |
||||
|
||||
off = fdt_path_offset(blob, "/cpus"); |
||||
if (off < 0) { |
||||
puts("couldn't find /cpus node\n"); |
||||
return; |
||||
} |
||||
of_bus_default_count_cells(blob, off, &addr_cells, NULL); |
||||
|
||||
off = fdt_node_offset_by_prop_value(blob, -1, "device_type", "cpu", 4); |
||||
while (off != -FDT_ERR_NOTFOUND) { |
||||
reg = (fdt32_t *)fdt_getprop(blob, off, "reg", 0); |
||||
if (reg) { |
||||
val = spin_tbl_addr; |
||||
val += id_to_core(of_read_number(reg, addr_cells)) |
||||
* SPIN_TABLE_ELEM_SIZE; |
||||
val = cpu_to_fdt64(val); |
||||
fdt_setprop_string(blob, off, "enable-method", |
||||
"spin-table"); |
||||
fdt_setprop(blob, off, "cpu-release-addr", |
||||
&val, sizeof(val)); |
||||
} else { |
||||
puts("Warning: found cpu node without reg property\n"); |
||||
} |
||||
off = fdt_node_offset_by_prop_value(blob, off, "device_type", |
||||
"cpu", 4); |
||||
} |
||||
|
||||
fdt_add_mem_rsv(blob, (uintptr_t)&secondary_boot_code, |
||||
*boot_code_size); |
||||
} |
||||
#endif |
||||
|
||||
void ft_cpu_setup(void *blob, bd_t *bd) |
||||
{ |
||||
#ifdef CONFIG_MP |
||||
ft_fixup_cpu(blob); |
||||
#endif |
||||
} |
@ -0,0 +1,168 @@ |
||||
/*
|
||||
* Copyright 2014 Freescale Semiconductor, Inc. |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
*/ |
||||
|
||||
#include <common.h> |
||||
#include <asm/io.h> |
||||
#include <asm/system.h> |
||||
#include <asm/io.h> |
||||
#include <asm/arch-fsl-lsch3/immap_lsch3.h> |
||||
#include "mp.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; |
||||
} |
||||
|
||||
int fsl_lsch3_wake_seconday_cores(void) |
||||
{ |
||||
struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR); |
||||
struct ccsr_reset __iomem *rst = (void *)(CONFIG_SYS_FSL_RST_ADDR); |
||||
u32 cores, cpu_up_mask = 1; |
||||
int i, timeout = 10; |
||||
u64 *table = get_spin_tbl_addr(); |
||||
|
||||
cores = cpu_mask(); |
||||
/* Clear spin table so that secondary processors
|
||||
* observe the correct value after waking up from wfe. |
||||
*/ |
||||
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); |
||||
out_le32(&gur->bootlocptrh, (u32)(gd->relocaddr >> 32)); |
||||
out_le32(&gur->bootlocptrl, (u32)gd->relocaddr); |
||||
out_le32(&gur->scratchrw[6], 1); |
||||
asm volatile("dsb st" : : : "memory"); |
||||
rst->brrl = cores; |
||||
asm volatile("dsb st" : : : "memory"); |
||||
|
||||
/* This is needed as a precautionary measure.
|
||||
* If some code before this has accidentally released the secondary |
||||
* cores then the pre-bootloader code will trap them in a "wfe" unless |
||||
* the scratchrw[6] is set. In this case we need a sev here to get these |
||||
* cores moving again. |
||||
*/ |
||||
asm volatile("sev"); |
||||
|
||||
while (timeout--) { |
||||
flush_dcache_range((unsigned long)table, (unsigned long)table + |
||||
CONFIG_MAX_CPUS * 64); |
||||
for (i = 1; i < CONFIG_MAX_CPUS; i++) { |
||||
if (table[i * WORDS_PER_SPIN_TABLE_ENTRY + |
||||
SPIN_TABLE_ELEM_STATUS_IDX]) |
||||
cpu_up_mask |= 1 << i; |
||||
} |
||||
if (hweight32(cpu_up_mask) == hweight32(cores)) |
||||
break; |
||||
udelay(10); |
||||
} |
||||
if (timeout <= 0) { |
||||
printf("Not all cores (0x%x) are up (0x%x)\n", |
||||
cores, cpu_up_mask); |
||||
return 1; |
||||
} |
||||
printf("All (%d) cores are up.\n", hweight32(cores)); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
int is_core_valid(unsigned int core) |
||||
{ |
||||
return !!((1 << core) & cpu_mask()); |
||||
} |
||||
|
||||
int cpu_reset(int nr) |
||||
{ |
||||
puts("Feature is not implemented.\n"); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
int cpu_disable(int nr) |
||||
{ |
||||
puts("Feature is not implemented.\n"); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
int core_to_pos(int nr) |
||||
{ |
||||
u32 cores = cpu_mask(); |
||||
int i, count = 0; |
||||
|
||||
if (nr == 0) { |
||||
return 0; |
||||
} else if (nr >= hweight32(cores)) { |
||||
puts("Not a valid core number.\n"); |
||||
return -1; |
||||
} |
||||
|
||||
for (i = 1; i < 32; i++) { |
||||
if (is_core_valid(i)) { |
||||
count++; |
||||
if (count == nr) |
||||
break; |
||||
} |
||||
} |
||||
|
||||
return count; |
||||
} |
||||
|
||||
int cpu_status(int nr) |
||||
{ |
||||
u64 *table; |
||||
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; |
||||
printf("table @ 0x%p\n", table); |
||||
printf(" addr - 0x%016llx\n", |
||||
table[SPIN_TABLE_ELEM_ENTRY_ADDR_IDX]); |
||||
printf(" status - 0x%016llx\n", |
||||
table[SPIN_TABLE_ELEM_STATUS_IDX]); |
||||
printf(" lpid - 0x%016llx\n", |
||||
table[SPIN_TABLE_ELEM_LPID_IDX]); |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
int cpu_release(int nr, int argc, char * const argv[]) |
||||
{ |
||||
u64 boot_addr; |
||||
u64 *table = (u64 *)get_spin_tbl_addr(); |
||||
int pos; |
||||
|
||||
pos = core_to_pos(nr); |
||||
if (pos <= 0) |
||||
return -1; |
||||
|
||||
table += pos * WORDS_PER_SPIN_TABLE_ENTRY; |
||||
boot_addr = simple_strtoull(argv[0], NULL, 16); |
||||
table[SPIN_TABLE_ELEM_ENTRY_ADDR_IDX] = boot_addr; |
||||
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 */ |
||||
|
||||
return 0; |
||||
} |
@ -0,0 +1,36 @@ |
||||
/*
|
||||
* Copyright 2014, Freescale Semiconductor |
||||
* |
||||
* SPDX-License-Identifier: GPL-2.0+ |
||||
*/ |
||||
|
||||
#ifndef _FSL_CH3_MP_H |
||||
#define _FSL_CH3_MP_H |
||||
|
||||
/*
|
||||
* Each spin table element is defined as |
||||
* struct { |
||||
* uint64_t entry_addr; |
||||
* uint64_t status; |
||||
* uint64_t lpid; |
||||
* }; |
||||
* we pad this struct to 64 bytes so each entry is in its own cacheline |
||||
* the actual spin table is an array of these structures |
||||
*/ |
||||
#define SPIN_TABLE_ELEM_ENTRY_ADDR_IDX 0 |
||||
#define SPIN_TABLE_ELEM_STATUS_IDX 1 |
||||
#define SPIN_TABLE_ELEM_LPID_IDX 2 |
||||
#define WORDS_PER_SPIN_TABLE_ENTRY 8 /* pad to 64 bytes */ |
||||
#define SPIN_TABLE_ELEM_SIZE 64 |
||||
|
||||
#define id_to_core(x) ((x & 3) | (x >> 6)) |
||||
#ifndef __ASSEMBLY__ |
||||
extern u64 __spin_table[]; |
||||
extern u64 *secondary_boot_code; |
||||
extern size_t __secondary_boot_code_size; |
||||
int fsl_lsch3_wake_seconday_cores(void); |
||||
void *get_spin_tbl_addr(void); |
||||
phys_addr_t determine_mp_bootpg(void); |
||||
void secondary_boot_func(void); |
||||
#endif |
||||
#endif /* _FSL_CH3_MP_H */ |
Loading…
Reference in new issue