162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * linux/arch/arm/mach-axxia/platsmp.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2012 LSI Corporation
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/init.h>
962306a36Sopenharmony_ci#include <linux/io.h>
1062306a36Sopenharmony_ci#include <linux/smp.h>
1162306a36Sopenharmony_ci#include <linux/of.h>
1262306a36Sopenharmony_ci#include <linux/of_address.h>
1362306a36Sopenharmony_ci#include <asm/cacheflush.h>
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci/* Syscon register offsets for releasing cores from reset */
1662306a36Sopenharmony_ci#define SC_CRIT_WRITE_KEY	0x1000
1762306a36Sopenharmony_ci#define SC_RST_CPU_HOLD		0x1010
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci/*
2062306a36Sopenharmony_ci * Write the kernel entry point for secondary CPUs to the specified address
2162306a36Sopenharmony_ci */
2262306a36Sopenharmony_cistatic void write_release_addr(u32 release_phys)
2362306a36Sopenharmony_ci{
2462306a36Sopenharmony_ci	u32 *virt = (u32 *) phys_to_virt(release_phys);
2562306a36Sopenharmony_ci	writel_relaxed(__pa_symbol(secondary_startup), virt);
2662306a36Sopenharmony_ci	/* Make sure this store is visible to other CPUs */
2762306a36Sopenharmony_ci	smp_wmb();
2862306a36Sopenharmony_ci	__cpuc_flush_dcache_area(virt, sizeof(u32));
2962306a36Sopenharmony_ci}
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_cistatic int axxia_boot_secondary(unsigned int cpu, struct task_struct *idle)
3262306a36Sopenharmony_ci{
3362306a36Sopenharmony_ci	struct device_node *syscon_np;
3462306a36Sopenharmony_ci	void __iomem *syscon;
3562306a36Sopenharmony_ci	u32 tmp;
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci	syscon_np = of_find_compatible_node(NULL, NULL, "lsi,axxia-syscon");
3862306a36Sopenharmony_ci	if (!syscon_np)
3962306a36Sopenharmony_ci		return -ENOENT;
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci	syscon = of_iomap(syscon_np, 0);
4262306a36Sopenharmony_ci	of_node_put(syscon_np);
4362306a36Sopenharmony_ci	if (!syscon)
4462306a36Sopenharmony_ci		return -ENOMEM;
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci	tmp = readl(syscon + SC_RST_CPU_HOLD);
4762306a36Sopenharmony_ci	writel(0xab, syscon + SC_CRIT_WRITE_KEY);
4862306a36Sopenharmony_ci	tmp &= ~(1 << cpu);
4962306a36Sopenharmony_ci	writel(tmp, syscon + SC_RST_CPU_HOLD);
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci	return 0;
5262306a36Sopenharmony_ci}
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_cistatic void __init axxia_smp_prepare_cpus(unsigned int max_cpus)
5562306a36Sopenharmony_ci{
5662306a36Sopenharmony_ci	int cpu_count = 0;
5762306a36Sopenharmony_ci	int cpu;
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	/*
6062306a36Sopenharmony_ci	 * Initialise the present map, which describes the set of CPUs actually
6162306a36Sopenharmony_ci	 * populated at the present time.
6262306a36Sopenharmony_ci	 */
6362306a36Sopenharmony_ci	for_each_possible_cpu(cpu) {
6462306a36Sopenharmony_ci		struct device_node *np;
6562306a36Sopenharmony_ci		u32 release_phys;
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci		np = of_get_cpu_node(cpu, NULL);
6862306a36Sopenharmony_ci		if (!np)
6962306a36Sopenharmony_ci			continue;
7062306a36Sopenharmony_ci		if (of_property_read_u32(np, "cpu-release-addr", &release_phys))
7162306a36Sopenharmony_ci			continue;
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci		if (cpu_count < max_cpus) {
7462306a36Sopenharmony_ci			set_cpu_present(cpu, true);
7562306a36Sopenharmony_ci			cpu_count++;
7662306a36Sopenharmony_ci		}
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci		if (release_phys != 0)
7962306a36Sopenharmony_ci			write_release_addr(release_phys);
8062306a36Sopenharmony_ci	}
8162306a36Sopenharmony_ci}
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_cistatic const struct smp_operations axxia_smp_ops __initconst = {
8462306a36Sopenharmony_ci	.smp_prepare_cpus	= axxia_smp_prepare_cpus,
8562306a36Sopenharmony_ci	.smp_boot_secondary	= axxia_boot_secondary,
8662306a36Sopenharmony_ci};
8762306a36Sopenharmony_ciCPU_METHOD_OF_DECLARE(axxia_smp, "lsi,syscon-release", &axxia_smp_ops);
88