1d7445676SArnd Bergmann // SPDX-License-Identifier: GPL-2.0-only
2d7445676SArnd Bergmann /*
3d7445676SArnd Bergmann * Copyright (C) 2015 Linus Walleij
4d7445676SArnd Bergmann */
5d7445676SArnd Bergmann #include <linux/smp.h>
6d7445676SArnd Bergmann #include <linux/io.h>
7d7445676SArnd Bergmann #include <linux/of.h>
8d7445676SArnd Bergmann #include <linux/of_address.h>
9d7445676SArnd Bergmann #include <linux/regmap.h>
10d7445676SArnd Bergmann #include <linux/mfd/syscon.h>
11d7445676SArnd Bergmann
12d7445676SArnd Bergmann #include <asm/cacheflush.h>
13d7445676SArnd Bergmann #include <asm/smp_plat.h>
14d7445676SArnd Bergmann #include <asm/smp_scu.h>
15d7445676SArnd Bergmann
16d7445676SArnd Bergmann #include "platsmp.h"
17d7445676SArnd Bergmann
18d7445676SArnd Bergmann #define REALVIEW_SYS_FLAGSSET_OFFSET 0x30
19d7445676SArnd Bergmann
20d7445676SArnd Bergmann static const struct of_device_id realview_scu_match[] = {
21d7445676SArnd Bergmann { .compatible = "arm,arm11mp-scu", },
22d7445676SArnd Bergmann { .compatible = "arm,cortex-a9-scu", },
23d7445676SArnd Bergmann { .compatible = "arm,cortex-a5-scu", },
24d7445676SArnd Bergmann { }
25d7445676SArnd Bergmann };
26d7445676SArnd Bergmann
27d7445676SArnd Bergmann static const struct of_device_id realview_syscon_match[] = {
28d7445676SArnd Bergmann { .compatible = "arm,core-module-integrator", },
29d7445676SArnd Bergmann { .compatible = "arm,realview-eb-syscon", },
30d7445676SArnd Bergmann { .compatible = "arm,realview-pb11mp-syscon", },
31d7445676SArnd Bergmann { .compatible = "arm,realview-pbx-syscon", },
32d7445676SArnd Bergmann { },
33d7445676SArnd Bergmann };
34d7445676SArnd Bergmann
realview_smp_prepare_cpus(unsigned int max_cpus)35d7445676SArnd Bergmann static void __init realview_smp_prepare_cpus(unsigned int max_cpus)
36d7445676SArnd Bergmann {
37d7445676SArnd Bergmann struct device_node *np;
38d7445676SArnd Bergmann void __iomem *scu_base;
39d7445676SArnd Bergmann struct regmap *map;
40d7445676SArnd Bergmann unsigned int ncores;
41d7445676SArnd Bergmann int i;
42d7445676SArnd Bergmann
43d7445676SArnd Bergmann np = of_find_matching_node(NULL, realview_scu_match);
44d7445676SArnd Bergmann if (!np) {
45d7445676SArnd Bergmann pr_err("PLATSMP: No SCU base address\n");
46d7445676SArnd Bergmann return;
47d7445676SArnd Bergmann }
48d7445676SArnd Bergmann scu_base = of_iomap(np, 0);
49d7445676SArnd Bergmann of_node_put(np);
50d7445676SArnd Bergmann if (!scu_base) {
51d7445676SArnd Bergmann pr_err("PLATSMP: No SCU remap\n");
52d7445676SArnd Bergmann return;
53d7445676SArnd Bergmann }
54d7445676SArnd Bergmann
55d7445676SArnd Bergmann scu_enable(scu_base);
56d7445676SArnd Bergmann ncores = scu_get_core_count(scu_base);
57d7445676SArnd Bergmann pr_info("SCU: %d cores detected\n", ncores);
58d7445676SArnd Bergmann for (i = 0; i < ncores; i++)
59d7445676SArnd Bergmann set_cpu_possible(i, true);
60d7445676SArnd Bergmann iounmap(scu_base);
61d7445676SArnd Bergmann
62d7445676SArnd Bergmann /* The syscon contains the magic SMP start address registers */
63d7445676SArnd Bergmann np = of_find_matching_node(NULL, realview_syscon_match);
64d7445676SArnd Bergmann if (!np) {
65d7445676SArnd Bergmann pr_err("PLATSMP: No syscon match\n");
66d7445676SArnd Bergmann return;
67d7445676SArnd Bergmann }
68d7445676SArnd Bergmann map = syscon_node_to_regmap(np);
69*b2cce50aSKrzysztof Kozlowski of_node_put(np);
70d7445676SArnd Bergmann if (IS_ERR(map)) {
71d7445676SArnd Bergmann pr_err("PLATSMP: No syscon regmap\n");
72d7445676SArnd Bergmann return;
73d7445676SArnd Bergmann }
74d7445676SArnd Bergmann /* Put the boot address in this magic register */
75d7445676SArnd Bergmann regmap_write(map, REALVIEW_SYS_FLAGSSET_OFFSET,
76d7445676SArnd Bergmann __pa_symbol(versatile_secondary_startup));
77d7445676SArnd Bergmann }
78d7445676SArnd Bergmann
79d7445676SArnd Bergmann #ifdef CONFIG_HOTPLUG_CPU
realview_cpu_die(unsigned int cpu)80d7445676SArnd Bergmann static void realview_cpu_die(unsigned int cpu)
81d7445676SArnd Bergmann {
82d7445676SArnd Bergmann return versatile_immitation_cpu_die(cpu, 0x20);
83d7445676SArnd Bergmann }
84d7445676SArnd Bergmann #endif
85d7445676SArnd Bergmann
86d7445676SArnd Bergmann static const struct smp_operations realview_dt_smp_ops __initconst = {
87d7445676SArnd Bergmann .smp_prepare_cpus = realview_smp_prepare_cpus,
88d7445676SArnd Bergmann .smp_secondary_init = versatile_secondary_init,
89d7445676SArnd Bergmann .smp_boot_secondary = versatile_boot_secondary,
90d7445676SArnd Bergmann #ifdef CONFIG_HOTPLUG_CPU
91d7445676SArnd Bergmann .cpu_die = realview_cpu_die,
92d7445676SArnd Bergmann #endif
93d7445676SArnd Bergmann };
94d7445676SArnd Bergmann CPU_METHOD_OF_DECLARE(realview_smp, "arm,realview-smp", &realview_dt_smp_ops);
95