mirror of https://github.com/Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
86 lines
2.0 KiB
86 lines
2.0 KiB
// SPDX-License-Identifier: GPL-2.0-only |
|
/* |
|
* linux/arch/arm/mach-axxia/platsmp.c |
|
* |
|
* Copyright (C) 2012 LSI Corporation |
|
*/ |
|
|
|
#include <linux/init.h> |
|
#include <linux/io.h> |
|
#include <linux/smp.h> |
|
#include <linux/of.h> |
|
#include <linux/of_address.h> |
|
#include <asm/cacheflush.h> |
|
|
|
/* Syscon register offsets for releasing cores from reset */ |
|
#define SC_CRIT_WRITE_KEY 0x1000 |
|
#define SC_RST_CPU_HOLD 0x1010 |
|
|
|
/* |
|
* Write the kernel entry point for secondary CPUs to the specified address |
|
*/ |
|
static void write_release_addr(u32 release_phys) |
|
{ |
|
u32 *virt = (u32 *) phys_to_virt(release_phys); |
|
writel_relaxed(__pa_symbol(secondary_startup), virt); |
|
/* Make sure this store is visible to other CPUs */ |
|
smp_wmb(); |
|
__cpuc_flush_dcache_area(virt, sizeof(u32)); |
|
} |
|
|
|
static int axxia_boot_secondary(unsigned int cpu, struct task_struct *idle) |
|
{ |
|
struct device_node *syscon_np; |
|
void __iomem *syscon; |
|
u32 tmp; |
|
|
|
syscon_np = of_find_compatible_node(NULL, NULL, "lsi,axxia-syscon"); |
|
if (!syscon_np) |
|
return -ENOENT; |
|
|
|
syscon = of_iomap(syscon_np, 0); |
|
if (!syscon) |
|
return -ENOMEM; |
|
|
|
tmp = readl(syscon + SC_RST_CPU_HOLD); |
|
writel(0xab, syscon + SC_CRIT_WRITE_KEY); |
|
tmp &= ~(1 << cpu); |
|
writel(tmp, syscon + SC_RST_CPU_HOLD); |
|
|
|
return 0; |
|
} |
|
|
|
static void __init axxia_smp_prepare_cpus(unsigned int max_cpus) |
|
{ |
|
int cpu_count = 0; |
|
int cpu; |
|
|
|
/* |
|
* Initialise the present map, which describes the set of CPUs actually |
|
* populated at the present time. |
|
*/ |
|
for_each_possible_cpu(cpu) { |
|
struct device_node *np; |
|
u32 release_phys; |
|
|
|
np = of_get_cpu_node(cpu, NULL); |
|
if (!np) |
|
continue; |
|
if (of_property_read_u32(np, "cpu-release-addr", &release_phys)) |
|
continue; |
|
|
|
if (cpu_count < max_cpus) { |
|
set_cpu_present(cpu, true); |
|
cpu_count++; |
|
} |
|
|
|
if (release_phys != 0) |
|
write_release_addr(release_phys); |
|
} |
|
} |
|
|
|
static const struct smp_operations axxia_smp_ops __initconst = { |
|
.smp_prepare_cpus = axxia_smp_prepare_cpus, |
|
.smp_boot_secondary = axxia_boot_secondary, |
|
}; |
|
CPU_METHOD_OF_DECLARE(axxia_smp, "lsi,syscon-release", &axxia_smp_ops);
|
|
|