186 lines
3.7 KiB
C
186 lines
3.7 KiB
C
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
|
|
/*
|
|
* Copyright (c) 2019 Amlogic, Inc. All rights reserved.
|
|
*/
|
|
|
|
//#include <common.h>
|
|
#include <asm/system.h>
|
|
#include <asm/global_data.h>
|
|
#include <asm/arch-meson/smp.h>
|
|
#include <cpu_func.h>
|
|
#include <linux/delay.h>
|
|
|
|
DECLARE_GLOBAL_DATA_PTR;
|
|
|
|
typedef enum {
|
|
AFF_STATE_ON = 0,
|
|
AFF_STATE_OFF = 1,
|
|
AFF_STATE_ON_PENDING = 2
|
|
} aff_info_state_t;
|
|
|
|
unsigned int __cpu_online_mask;
|
|
unsigned int __num_online_cpus;
|
|
struct smp_boot_param smp_boot[NR_CPUS];
|
|
|
|
void set_cpu_online(unsigned int cpu, bool online)
|
|
{
|
|
/*
|
|
* atomic_inc/dec() is required to handle the horrid abuse of this
|
|
* function by the reboot and kexec code which invoke it from
|
|
* IPI/NMI broadcasts when shutting down CPUs. Invocation from
|
|
* regular CPU hotplug is properly serialized.
|
|
*
|
|
* Note, that the fact that __num_online_cpus is of type atomic_t
|
|
* does not protect readers which are not serialized against
|
|
* concurrent hotplug operations.
|
|
*/
|
|
if (online) {
|
|
__cpu_online_mask |= (1 << cpu);
|
|
__num_online_cpus++;
|
|
|
|
} else {
|
|
__cpu_online_mask &= ~(1 << cpu);
|
|
}
|
|
}
|
|
|
|
unsigned int cpu_online(unsigned int cpu)
|
|
{
|
|
return (__cpu_online_mask >> cpu) & 0x1;
|
|
}
|
|
|
|
unsigned int cpu_online_status(void)
|
|
{
|
|
return __cpu_online_mask;
|
|
}
|
|
|
|
/*
|
|
* Activate the first processor.
|
|
*/
|
|
void boot_cpu_init(void)
|
|
{
|
|
/* Mark the boot cpu "present", "online" etc for SMP and UP case */
|
|
set_cpu_online(0, true);
|
|
flush_dcache_all();
|
|
}
|
|
|
|
int cpu_up(unsigned int cpu, unsigned int entrypoint)
|
|
{
|
|
return psci_cpu_on(cpu, entrypoint);
|
|
}
|
|
|
|
void cpu_off(void)
|
|
{
|
|
psci_cpu_off();
|
|
}
|
|
|
|
static int secondary_boot(unsigned int cpu, unsigned int entrypoint)
|
|
{
|
|
int ret = -1;
|
|
|
|
/* Skip online CPUs and CPUs on offline nodes */
|
|
if (cpu_online(cpu))
|
|
return 0;
|
|
|
|
boot_cpu_init();
|
|
|
|
ret = cpu_up(cpu, entrypoint);
|
|
if (ret == 0) {
|
|
udelay(1000);
|
|
__asm__ volatile("sev");
|
|
udelay(100);
|
|
if (cpu_online(cpu)) {
|
|
printf("CPU%u: come online\n", cpu);
|
|
} else {
|
|
printf("CPU%u: failed to come online\n", cpu);
|
|
ret = -1;
|
|
}
|
|
} else {
|
|
printf("CPU%u: failed to boot\n", cpu);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
unsigned int get_core_id(void)
|
|
{
|
|
unsigned long mpidr = read_mpidr();
|
|
unsigned int cpuid;
|
|
|
|
if (mpidr & (1 << 24))
|
|
mpidr = mpidr >> 8;
|
|
cpuid = mpidr & 0xff;
|
|
mpidr = (mpidr >> 8) & 0xff;
|
|
if (mpidr) /* cluster 1 */
|
|
cpuid = cpuid + 4; /* meson soc cluster 0 has 4 cores */
|
|
|
|
return cpuid;
|
|
}
|
|
|
|
void secondary_off(void)
|
|
{
|
|
unsigned long mpidr = read_mpidr();
|
|
unsigned int cpu;
|
|
|
|
if (mpidr & (1 << 24))
|
|
mpidr = mpidr >> 8;
|
|
cpu = mpidr & 0xff;
|
|
mpidr = (mpidr >> 8) & 0xff;
|
|
if (mpidr) /* cluster 1 */
|
|
cpu = cpu + 4; /* meson soc cluster 0 has 4 cores*/
|
|
|
|
if (cpu >= NR_CPUS)
|
|
return;
|
|
set_cpu_online(cpu, 0);
|
|
dcache_disable();
|
|
cpu_off();
|
|
}
|
|
|
|
void secondary_start(void)
|
|
{
|
|
unsigned long mpidr = read_mpidr();
|
|
unsigned int cpu;
|
|
|
|
enable_caches();
|
|
if (mpidr & (1 << 24))
|
|
mpidr = mpidr >> 8;
|
|
cpu = mpidr & 0xff;
|
|
mpidr = (mpidr >> 8) & 0xff;
|
|
if (mpidr) /* cluster 1 */
|
|
cpu = cpu + 4; /* meson soc cluster 0 has 4 cores*/
|
|
if (cpu >= NR_CPUS)
|
|
return;
|
|
set_cpu_online(cpu, true);
|
|
|
|
if (smp_boot[cpu].bootup)
|
|
smp_boot[cpu].bootup(smp_boot[cpu].param);
|
|
}
|
|
|
|
int is_secondary_core_power_on(void)
|
|
{
|
|
unsigned int i = 0, pwsts = 0;
|
|
|
|
if (__num_online_cpus > NR_CPUS)
|
|
__num_online_cpus = NR_CPUS;
|
|
|
|
for (i = 1; i < __num_online_cpus; i++) {
|
|
if (psci_get_aff_info(i) != AFF_STATE_OFF)
|
|
pwsts |= (1 << i);
|
|
}
|
|
|
|
return pwsts;
|
|
}
|
|
|
|
int run_smp_function(unsigned int cpu, void (*func)(unsigned long arg), unsigned long arg)
|
|
{
|
|
int ret;
|
|
|
|
if (cpu >= NR_CPUS) {
|
|
printf("CPU%u larger than max cpuidx %d\n", cpu, NR_CPUS - 1);
|
|
return -1;
|
|
}
|
|
smp_boot[cpu].bootup = func;
|
|
smp_boot[cpu].param = arg;
|
|
ret = secondary_boot(cpu, (unsigned int)gd->relocaddr);
|
|
|
|
return ret;
|
|
}
|