Commit | Line | Data |
---|---|---|
d2912cb1 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
59ac59f6 RK |
2 | /* |
3 | * linux/arch/arm/mach-vexpress/platsmp.c | |
4 | * | |
5 | * Copyright (C) 2002 ARM Ltd. | |
6 | * All Rights Reserved | |
59ac59f6 RK |
7 | */ |
8 | #include <linux/init.h> | |
9 | #include <linux/errno.h> | |
59ac59f6 RK |
10 | #include <linux/smp.h> |
11 | #include <linux/io.h> | |
d2606f81 | 12 | #include <linux/of_address.h> |
38669e04 | 13 | #include <linux/vexpress.h> |
95d59741 | 14 | |
033a899c | 15 | #include <asm/mcpm.h> |
95d59741 | 16 | #include <asm/smp_scu.h> |
95d59741 | 17 | #include <asm/mach/map.h> |
59ac59f6 | 18 | |
3695adc2 | 19 | #include <plat/platsmp.h> |
59ac59f6 | 20 | |
3695adc2 | 21 | #include "core.h" |
3705ff6d | 22 | |
033a899c JM |
23 | bool __init vexpress_smp_init_ops(void) |
24 | { | |
25 | #ifdef CONFIG_MCPM | |
525d4015 LP |
26 | int cpu; |
27 | struct device_node *cpu_node, *cci_node; | |
28 | ||
033a899c | 29 | /* |
525d4015 LP |
30 | * The best way to detect a multi-cluster configuration |
31 | * is to detect if the kernel can take over CCI ports | |
32 | * control. Loop over possible CPUs and check if CCI | |
33 | * port control is available. | |
033a899c JM |
34 | * Override the default vexpress_smp_ops if so. |
35 | */ | |
525d4015 LP |
36 | for_each_possible_cpu(cpu) { |
37 | bool available; | |
38 | ||
39 | cpu_node = of_get_cpu_node(cpu, NULL); | |
40 | if (WARN(!cpu_node, "Missing cpu device node!")) | |
41 | return false; | |
42 | ||
43 | cci_node = of_parse_phandle(cpu_node, "cci-control-port", 0); | |
44 | available = cci_node && of_device_is_available(cci_node); | |
45 | of_node_put(cci_node); | |
46 | of_node_put(cpu_node); | |
47 | ||
48 | if (!available) | |
49 | return false; | |
033a899c | 50 | } |
525d4015 LP |
51 | |
52 | mcpm_smp_set_ops(); | |
53 | return true; | |
54 | #else | |
033a899c | 55 | return false; |
525d4015 | 56 | #endif |
033a899c | 57 | } |
d2606f81 | 58 | |
d2606f81 PM |
59 | static const struct of_device_id vexpress_smp_dt_scu_match[] __initconst = { |
60 | { .compatible = "arm,cortex-a5-scu", }, | |
61 | { .compatible = "arm,cortex-a9-scu", }, | |
62 | {} | |
63 | }; | |
64 | ||
65 | static void __init vexpress_smp_dt_prepare_cpus(unsigned int max_cpus) | |
66 | { | |
67 | struct device_node *scu = of_find_matching_node(NULL, | |
68 | vexpress_smp_dt_scu_match); | |
69 | ||
70 | if (scu) | |
71 | scu_enable(of_iomap(scu, 0)); | |
72 | ||
73 | /* | |
74 | * Write the address of secondary startup into the | |
75 | * system-wide flags register. The boot monitor waits | |
76 | * until it receives a soft interrupt, and then the | |
77 | * secondary CPU branches to this address. | |
78 | */ | |
64fc2a94 | 79 | vexpress_flags_set(__pa_symbol(versatile_secondary_startup)); |
d2606f81 PM |
80 | } |
81 | ||
4fb68e12 RK |
82 | #ifdef CONFIG_HOTPLUG_CPU |
83 | static void vexpress_cpu_die(unsigned int cpu) | |
84 | { | |
85 | versatile_immitation_cpu_die(cpu, 0x40); | |
86 | } | |
87 | #endif | |
88 | ||
75305275 | 89 | const struct smp_operations vexpress_smp_dt_ops __initconst = { |
d2606f81 PM |
90 | .smp_prepare_cpus = vexpress_smp_dt_prepare_cpus, |
91 | .smp_secondary_init = versatile_secondary_init, | |
92 | .smp_boot_secondary = versatile_boot_secondary, | |
93 | #ifdef CONFIG_HOTPLUG_CPU | |
94 | .cpu_die = vexpress_cpu_die, | |
95 | #endif | |
96 | }; |