Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/arm/mach-mvebu/platsmp-a9.c
26292 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
/*
3
* Symmetric Multi Processing (SMP) support for Marvell EBU Cortex-A9
4
* based SOCs (Armada 375/38x).
5
*
6
* Copyright (C) 2014 Marvell
7
*
8
* Gregory CLEMENT <[email protected]>
9
* Thomas Petazzoni <[email protected]>
10
*/
11
12
#include <linux/init.h>
13
#include <linux/io.h>
14
#include <linux/of.h>
15
#include <linux/smp.h>
16
#include <linux/mbus.h>
17
#include <asm/smp_scu.h>
18
#include <asm/smp_plat.h>
19
#include "common.h"
20
#include "pmsu.h"
21
22
extern void mvebu_cortex_a9_secondary_startup(void);
23
24
static int mvebu_cortex_a9_boot_secondary(unsigned int cpu,
25
struct task_struct *idle)
26
{
27
int ret, hw_cpu;
28
29
pr_info("Booting CPU %d\n", cpu);
30
31
/*
32
* Write the address of secondary startup into the system-wide
33
* flags register. The boot monitor waits until it receives a
34
* soft interrupt, and then the secondary CPU branches to this
35
* address.
36
*/
37
hw_cpu = cpu_logical_map(cpu);
38
if (of_machine_is_compatible("marvell,armada375"))
39
mvebu_system_controller_set_cpu_boot_addr(mvebu_cortex_a9_secondary_startup);
40
else
41
mvebu_pmsu_set_cpu_boot_addr(hw_cpu, mvebu_cortex_a9_secondary_startup);
42
smp_wmb();
43
44
/*
45
* Doing this before deasserting the CPUs is needed to wake up CPUs
46
* in the offline state after using CPU hotplug.
47
*/
48
arch_send_wakeup_ipi_mask(cpumask_of(cpu));
49
50
ret = mvebu_cpu_reset_deassert(hw_cpu);
51
if (ret) {
52
pr_err("Could not start the secondary CPU: %d\n", ret);
53
return ret;
54
}
55
56
return 0;
57
}
58
/*
59
* When a CPU is brought back online, either through CPU hotplug, or
60
* because of the boot of a kexec'ed kernel, the PMSU configuration
61
* for this CPU might be in the deep idle state, preventing this CPU
62
* from receiving interrupts. Here, we therefore take out the current
63
* CPU from this state, which was entered by armada_38x_cpu_die()
64
* below.
65
*/
66
static void armada_38x_secondary_init(unsigned int cpu)
67
{
68
mvebu_v7_pmsu_idle_exit();
69
}
70
71
#ifdef CONFIG_HOTPLUG_CPU
72
static void armada_38x_cpu_die(unsigned int cpu)
73
{
74
/*
75
* CPU hotplug is implemented by putting offline CPUs into the
76
* deep idle sleep state.
77
*/
78
armada_38x_do_cpu_suspend(true);
79
}
80
81
/*
82
* We need a dummy function, so that platform_can_cpu_hotplug() knows
83
* we support CPU hotplug. However, the function does not need to do
84
* anything, because CPUs going offline can enter the deep idle state
85
* by themselves, without any help from a still alive CPU.
86
*/
87
static int armada_38x_cpu_kill(unsigned int cpu)
88
{
89
return 1;
90
}
91
#endif
92
93
static const struct smp_operations mvebu_cortex_a9_smp_ops __initconst = {
94
.smp_boot_secondary = mvebu_cortex_a9_boot_secondary,
95
};
96
97
static const struct smp_operations armada_38x_smp_ops __initconst = {
98
.smp_boot_secondary = mvebu_cortex_a9_boot_secondary,
99
.smp_secondary_init = armada_38x_secondary_init,
100
#ifdef CONFIG_HOTPLUG_CPU
101
.cpu_die = armada_38x_cpu_die,
102
.cpu_kill = armada_38x_cpu_kill,
103
#endif
104
};
105
106
CPU_METHOD_OF_DECLARE(mvebu_armada_375_smp, "marvell,armada-375-smp",
107
&mvebu_cortex_a9_smp_ops);
108
CPU_METHOD_OF_DECLARE(mvebu_armada_380_smp, "marvell,armada-380-smp",
109
&armada_38x_smp_ops);
110
CPU_METHOD_OF_DECLARE(mvebu_armada_390_smp, "marvell,armada-390-smp",
111
&armada_38x_smp_ops);
112
113