162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * linux/arch/arm/mach-vexpress/mcpm_platsmp.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Created by:  Nicolas Pitre, November 2012
662306a36Sopenharmony_ci * Copyright:   (C) 2012-2013  Linaro Limited
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * Code to handle secondary CPU bringup and hotplug for the cluster power API.
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <linux/init.h>
1262306a36Sopenharmony_ci#include <linux/smp.h>
1362306a36Sopenharmony_ci#include <linux/spinlock.h>
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#include <asm/mcpm.h>
1662306a36Sopenharmony_ci#include <asm/smp.h>
1762306a36Sopenharmony_ci#include <asm/smp_plat.h>
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_cistatic void cpu_to_pcpu(unsigned int cpu,
2062306a36Sopenharmony_ci			unsigned int *pcpu, unsigned int *pcluster)
2162306a36Sopenharmony_ci{
2262306a36Sopenharmony_ci	unsigned int mpidr;
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci	mpidr = cpu_logical_map(cpu);
2562306a36Sopenharmony_ci	*pcpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
2662306a36Sopenharmony_ci	*pcluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
2762306a36Sopenharmony_ci}
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_cistatic int mcpm_boot_secondary(unsigned int cpu, struct task_struct *idle)
3062306a36Sopenharmony_ci{
3162306a36Sopenharmony_ci	unsigned int pcpu, pcluster, ret;
3262306a36Sopenharmony_ci	extern void secondary_startup(void);
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci	cpu_to_pcpu(cpu, &pcpu, &pcluster);
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci	pr_debug("%s: logical CPU %d is physical CPU %d cluster %d\n",
3762306a36Sopenharmony_ci		 __func__, cpu, pcpu, pcluster);
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci	mcpm_set_entry_vector(pcpu, pcluster, NULL);
4062306a36Sopenharmony_ci	ret = mcpm_cpu_power_up(pcpu, pcluster);
4162306a36Sopenharmony_ci	if (ret)
4262306a36Sopenharmony_ci		return ret;
4362306a36Sopenharmony_ci	mcpm_set_entry_vector(pcpu, pcluster, secondary_startup);
4462306a36Sopenharmony_ci	arch_send_wakeup_ipi_mask(cpumask_of(cpu));
4562306a36Sopenharmony_ci	dsb_sev();
4662306a36Sopenharmony_ci	return 0;
4762306a36Sopenharmony_ci}
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_cistatic void mcpm_secondary_init(unsigned int cpu)
5062306a36Sopenharmony_ci{
5162306a36Sopenharmony_ci	mcpm_cpu_powered_up();
5262306a36Sopenharmony_ci}
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci#ifdef CONFIG_HOTPLUG_CPU
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_cistatic int mcpm_cpu_kill(unsigned int cpu)
5762306a36Sopenharmony_ci{
5862306a36Sopenharmony_ci	unsigned int pcpu, pcluster;
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	cpu_to_pcpu(cpu, &pcpu, &pcluster);
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci	return !mcpm_wait_for_cpu_powerdown(pcpu, pcluster);
6362306a36Sopenharmony_ci}
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_cistatic bool mcpm_cpu_can_disable(unsigned int cpu)
6662306a36Sopenharmony_ci{
6762306a36Sopenharmony_ci	/* We assume all CPUs may be shut down. */
6862306a36Sopenharmony_ci	return true;
6962306a36Sopenharmony_ci}
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_cistatic void mcpm_cpu_die(unsigned int cpu)
7262306a36Sopenharmony_ci{
7362306a36Sopenharmony_ci	unsigned int mpidr, pcpu, pcluster;
7462306a36Sopenharmony_ci	mpidr = read_cpuid_mpidr();
7562306a36Sopenharmony_ci	pcpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
7662306a36Sopenharmony_ci	pcluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
7762306a36Sopenharmony_ci	mcpm_set_entry_vector(pcpu, pcluster, NULL);
7862306a36Sopenharmony_ci	mcpm_cpu_power_down();
7962306a36Sopenharmony_ci}
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci#endif
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_cistatic const struct smp_operations mcpm_smp_ops __initconst = {
8462306a36Sopenharmony_ci	.smp_boot_secondary	= mcpm_boot_secondary,
8562306a36Sopenharmony_ci	.smp_secondary_init	= mcpm_secondary_init,
8662306a36Sopenharmony_ci#ifdef CONFIG_HOTPLUG_CPU
8762306a36Sopenharmony_ci	.cpu_kill		= mcpm_cpu_kill,
8862306a36Sopenharmony_ci	.cpu_can_disable	= mcpm_cpu_can_disable,
8962306a36Sopenharmony_ci	.cpu_die		= mcpm_cpu_die,
9062306a36Sopenharmony_ci#endif
9162306a36Sopenharmony_ci};
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_civoid __init mcpm_smp_set_ops(void)
9462306a36Sopenharmony_ci{
9562306a36Sopenharmony_ci	smp_set_ops(&mcpm_smp_ops);
9662306a36Sopenharmony_ci}
97