xref: /openbmc/linux/arch/arm/mach-versatile/platsmp-realview.c (revision 34d6f206a88c2651d216bd3487ac956a40b2ba8e)
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