xref: /openbmc/linux/arch/arm/mach-berlin/platsmp.c (revision 2612e3bbc0386368a850140a6c9b990cd496a5ec)
1eb14767cSJisheng Zhang // SPDX-License-Identifier: GPL-2.0
27b7dfdd2SAntoine Ténart /*
37b7dfdd2SAntoine Ténart  * Copyright (C) 2014 Marvell Technology Group Ltd.
47b7dfdd2SAntoine Ténart  *
57b7dfdd2SAntoine Ténart  * Antoine Ténart <antoine.tenart@free-electrons.com>
67b7dfdd2SAntoine Ténart  */
77b7dfdd2SAntoine Ténart 
87b7dfdd2SAntoine Ténart #include <linux/io.h>
97b7dfdd2SAntoine Ténart #include <linux/delay.h>
107b7dfdd2SAntoine Ténart #include <linux/of.h>
117b7dfdd2SAntoine Ténart #include <linux/of_address.h>
127b7dfdd2SAntoine Ténart 
137b7dfdd2SAntoine Ténart #include <asm/cacheflush.h>
14a7b3d5a7SJisheng Zhang #include <asm/cp15.h>
15*a9ff6961SLinus Walleij #include <asm/page.h>
167b7dfdd2SAntoine Ténart #include <asm/smp_plat.h>
177b7dfdd2SAntoine Ténart #include <asm/smp_scu.h>
187b7dfdd2SAntoine Ténart 
19ac7fc233SJisheng Zhang /*
20ac7fc233SJisheng Zhang  * There are two reset registers, one with self-clearing (SC)
21ac7fc233SJisheng Zhang  * reset and one with non-self-clearing reset (NON_SC).
22ac7fc233SJisheng Zhang  */
23ac7fc233SJisheng Zhang #define CPU_RESET_SC		0x00
24ac7fc233SJisheng Zhang #define CPU_RESET_NON_SC	0x20
257b7dfdd2SAntoine Ténart 
267b7dfdd2SAntoine Ténart #define RESET_VECT		0x00
277b7dfdd2SAntoine Ténart #define SW_RESET_ADDR		0x94
287b7dfdd2SAntoine Ténart 
297b7dfdd2SAntoine Ténart extern u32 boot_inst;
307b7dfdd2SAntoine Ténart 
317b7dfdd2SAntoine Ténart static void __iomem *cpu_ctrl;
327b7dfdd2SAntoine Ténart 
berlin_perform_reset_cpu(unsigned int cpu)337b7dfdd2SAntoine Ténart static inline void berlin_perform_reset_cpu(unsigned int cpu)
347b7dfdd2SAntoine Ténart {
357b7dfdd2SAntoine Ténart 	u32 val;
367b7dfdd2SAntoine Ténart 
37ac7fc233SJisheng Zhang 	val = readl(cpu_ctrl + CPU_RESET_NON_SC);
38ac7fc233SJisheng Zhang 	val &= ~BIT(cpu_logical_map(cpu));
39ac7fc233SJisheng Zhang 	writel(val, cpu_ctrl + CPU_RESET_NON_SC);
407b7dfdd2SAntoine Ténart 	val |= BIT(cpu_logical_map(cpu));
41ac7fc233SJisheng Zhang 	writel(val, cpu_ctrl + CPU_RESET_NON_SC);
427b7dfdd2SAntoine Ténart }
437b7dfdd2SAntoine Ténart 
berlin_boot_secondary(unsigned int cpu,struct task_struct * idle)447b7dfdd2SAntoine Ténart static int berlin_boot_secondary(unsigned int cpu, struct task_struct *idle)
457b7dfdd2SAntoine Ténart {
467b7dfdd2SAntoine Ténart 	if (!cpu_ctrl)
477b7dfdd2SAntoine Ténart 		return -EFAULT;
487b7dfdd2SAntoine Ténart 
497b7dfdd2SAntoine Ténart 	/*
507b7dfdd2SAntoine Ténart 	 * Reset the CPU, making it to execute the instruction in the reset
517b7dfdd2SAntoine Ténart 	 * exception vector.
527b7dfdd2SAntoine Ténart 	 */
537b7dfdd2SAntoine Ténart 	berlin_perform_reset_cpu(cpu);
547b7dfdd2SAntoine Ténart 
557b7dfdd2SAntoine Ténart 	return 0;
567b7dfdd2SAntoine Ténart }
577b7dfdd2SAntoine Ténart 
berlin_smp_prepare_cpus(unsigned int max_cpus)587b7dfdd2SAntoine Ténart static void __init berlin_smp_prepare_cpus(unsigned int max_cpus)
597b7dfdd2SAntoine Ténart {
607b7dfdd2SAntoine Ténart 	struct device_node *np;
617b7dfdd2SAntoine Ténart 	void __iomem *scu_base;
627b7dfdd2SAntoine Ténart 	void __iomem *vectors_base;
637b7dfdd2SAntoine Ténart 
647b7dfdd2SAntoine Ténart 	np = of_find_compatible_node(NULL, NULL, "arm,cortex-a9-scu");
657b7dfdd2SAntoine Ténart 	scu_base = of_iomap(np, 0);
667b7dfdd2SAntoine Ténart 	of_node_put(np);
677b7dfdd2SAntoine Ténart 	if (!scu_base)
687b7dfdd2SAntoine Ténart 		return;
697b7dfdd2SAntoine Ténart 
707b7dfdd2SAntoine Ténart 	np = of_find_compatible_node(NULL, NULL, "marvell,berlin-cpu-ctrl");
717b7dfdd2SAntoine Ténart 	cpu_ctrl = of_iomap(np, 0);
727b7dfdd2SAntoine Ténart 	of_node_put(np);
737b7dfdd2SAntoine Ténart 	if (!cpu_ctrl)
747b7dfdd2SAntoine Ténart 		goto unmap_scu;
757b7dfdd2SAntoine Ténart 
76d2ca5f24SAfzal Mohammed 	vectors_base = ioremap(VECTORS_BASE, SZ_32K);
777b7dfdd2SAntoine Ténart 	if (!vectors_base)
787b7dfdd2SAntoine Ténart 		goto unmap_scu;
797b7dfdd2SAntoine Ténart 
807b7dfdd2SAntoine Ténart 	scu_enable(scu_base);
817b7dfdd2SAntoine Ténart 
827b7dfdd2SAntoine Ténart 	/*
837b7dfdd2SAntoine Ténart 	 * Write the first instruction the CPU will execute after being reset
847b7dfdd2SAntoine Ténart 	 * in the reset exception vector.
857b7dfdd2SAntoine Ténart 	 */
867b7dfdd2SAntoine Ténart 	writel(boot_inst, vectors_base + RESET_VECT);
877b7dfdd2SAntoine Ténart 
887b7dfdd2SAntoine Ténart 	/*
897b7dfdd2SAntoine Ténart 	 * Write the secondary startup address into the SW reset address
907b7dfdd2SAntoine Ténart 	 * vector. This is used by boot_inst.
917b7dfdd2SAntoine Ténart 	 */
9264fc2a94SFlorian Fainelli 	writel(__pa_symbol(secondary_startup), vectors_base + SW_RESET_ADDR);
937b7dfdd2SAntoine Ténart 
947b7dfdd2SAntoine Ténart 	iounmap(vectors_base);
957b7dfdd2SAntoine Ténart unmap_scu:
967b7dfdd2SAntoine Ténart 	iounmap(scu_base);
977b7dfdd2SAntoine Ténart }
987b7dfdd2SAntoine Ténart 
99a7b3d5a7SJisheng Zhang #ifdef CONFIG_HOTPLUG_CPU
berlin_cpu_die(unsigned int cpu)100a7b3d5a7SJisheng Zhang static void berlin_cpu_die(unsigned int cpu)
101a7b3d5a7SJisheng Zhang {
102a7b3d5a7SJisheng Zhang 	v7_exit_coherency_flush(louis);
103a7b3d5a7SJisheng Zhang 	while (1)
104a7b3d5a7SJisheng Zhang 		cpu_do_idle();
105a7b3d5a7SJisheng Zhang }
106a7b3d5a7SJisheng Zhang 
berlin_cpu_kill(unsigned int cpu)107a7b3d5a7SJisheng Zhang static int berlin_cpu_kill(unsigned int cpu)
108a7b3d5a7SJisheng Zhang {
109a7b3d5a7SJisheng Zhang 	u32 val;
110a7b3d5a7SJisheng Zhang 
111a7b3d5a7SJisheng Zhang 	val = readl(cpu_ctrl + CPU_RESET_NON_SC);
112a7b3d5a7SJisheng Zhang 	val &= ~BIT(cpu_logical_map(cpu));
113a7b3d5a7SJisheng Zhang 	writel(val, cpu_ctrl + CPU_RESET_NON_SC);
114a7b3d5a7SJisheng Zhang 
115a7b3d5a7SJisheng Zhang 	return 1;
116a7b3d5a7SJisheng Zhang }
117a7b3d5a7SJisheng Zhang #endif
118a7b3d5a7SJisheng Zhang 
11975305275SMasahiro Yamada static const struct smp_operations berlin_smp_ops __initconst = {
1207b7dfdd2SAntoine Ténart 	.smp_prepare_cpus	= berlin_smp_prepare_cpus,
1217b7dfdd2SAntoine Ténart 	.smp_boot_secondary	= berlin_boot_secondary,
122a7b3d5a7SJisheng Zhang #ifdef CONFIG_HOTPLUG_CPU
123a7b3d5a7SJisheng Zhang 	.cpu_die		= berlin_cpu_die,
124a7b3d5a7SJisheng Zhang 	.cpu_kill		= berlin_cpu_kill,
125a7b3d5a7SJisheng Zhang #endif
1267b7dfdd2SAntoine Ténart };
1277b7dfdd2SAntoine Ténart CPU_METHOD_OF_DECLARE(berlin_smp, "marvell,berlin-smp", &berlin_smp_ops);
128