xref: /openbmc/linux/arch/arm/mach-socfpga/platsmp.c (revision 03ab8e6297acd1bc0eedaa050e2a1635c576fd11)
19952f691SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
29c4566a1SDinh Nguyen /*
39c4566a1SDinh Nguyen  * Copyright 2010-2011 Calxeda, Inc.
49c4566a1SDinh Nguyen  * Copyright 2012 Pavel Machek <pavel@denx.de>
59c4566a1SDinh Nguyen  * Based on platsmp.c, Copyright (C) 2002 ARM Ltd.
69c4566a1SDinh Nguyen  * Copyright (C) 2012 Altera Corporation
79c4566a1SDinh Nguyen  */
89c4566a1SDinh Nguyen #include <linux/delay.h>
99c4566a1SDinh Nguyen #include <linux/init.h>
109c4566a1SDinh Nguyen #include <linux/smp.h>
119c4566a1SDinh Nguyen #include <linux/io.h>
129c4566a1SDinh Nguyen #include <linux/of.h>
139c4566a1SDinh Nguyen #include <linux/of_address.h>
149c4566a1SDinh Nguyen 
159c4566a1SDinh Nguyen #include <asm/cacheflush.h>
169c4566a1SDinh Nguyen #include <asm/smp_scu.h>
179c4566a1SDinh Nguyen #include <asm/smp_plat.h>
189c4566a1SDinh Nguyen 
199c4566a1SDinh Nguyen #include "core.h"
209c4566a1SDinh Nguyen 
socfpga_boot_secondary(unsigned int cpu,struct task_struct * idle)218bd26e3aSPaul Gortmaker static int socfpga_boot_secondary(unsigned int cpu, struct task_struct *idle)
229c4566a1SDinh Nguyen {
23*187bea47STakashi Iwai 	int trampoline_size = secondary_trampoline_end - secondary_trampoline;
249c4566a1SDinh Nguyen 
253a4356c0SDinh Nguyen 	if (socfpga_cpu1start_addr) {
26d686ce42SAlan Tull 		/* This will put CPU #1 into reset. */
27d686ce42SAlan Tull 		writel(RSTMGR_MPUMODRST_CPU1,
28d686ce42SAlan Tull 		       rst_manager_base_addr + SOCFPGA_RSTMGR_MODMPURST);
29d686ce42SAlan Tull 
30*187bea47STakashi Iwai 		memcpy(phys_to_virt(0), secondary_trampoline, trampoline_size);
319c4566a1SDinh Nguyen 
3264fc2a94SFlorian Fainelli 		writel(__pa_symbol(secondary_startup),
33d686ce42SAlan Tull 		       sys_manager_base_addr + (socfpga_cpu1start_addr & 0x000000ff));
349c4566a1SDinh Nguyen 
359c4566a1SDinh Nguyen 		flush_cache_all();
369c4566a1SDinh Nguyen 		smp_wmb();
379c4566a1SDinh Nguyen 		outer_clean_range(0, trampoline_size);
389c4566a1SDinh Nguyen 
399c4566a1SDinh Nguyen 		/* This will release CPU #1 out of reset. */
40d686ce42SAlan Tull 		writel(0, rst_manager_base_addr + SOCFPGA_RSTMGR_MODMPURST);
41d6dd735fSDinh Nguyen 	}
429c4566a1SDinh Nguyen 
439c4566a1SDinh Nguyen 	return 0;
449c4566a1SDinh Nguyen }
459c4566a1SDinh Nguyen 
socfpga_a10_boot_secondary(unsigned int cpu,struct task_struct * idle)4645be0cdbSDinh Nguyen static int socfpga_a10_boot_secondary(unsigned int cpu, struct task_struct *idle)
479c4566a1SDinh Nguyen {
48*187bea47STakashi Iwai 	int trampoline_size = secondary_trampoline_end - secondary_trampoline;
499c4566a1SDinh Nguyen 
5045be0cdbSDinh Nguyen 	if (socfpga_cpu1start_addr) {
5145be0cdbSDinh Nguyen 		writel(RSTMGR_MPUMODRST_CPU1, rst_manager_base_addr +
5245be0cdbSDinh Nguyen 		       SOCFPGA_A10_RSTMGR_MODMPURST);
53*187bea47STakashi Iwai 		memcpy(phys_to_virt(0), secondary_trampoline, trampoline_size);
549c4566a1SDinh Nguyen 
5564fc2a94SFlorian Fainelli 		writel(__pa_symbol(secondary_startup),
5645be0cdbSDinh Nguyen 		       sys_manager_base_addr + (socfpga_cpu1start_addr & 0x00000fff));
579c4566a1SDinh Nguyen 
5845be0cdbSDinh Nguyen 		flush_cache_all();
5945be0cdbSDinh Nguyen 		smp_wmb();
6045be0cdbSDinh Nguyen 		outer_clean_range(0, trampoline_size);
6145be0cdbSDinh Nguyen 
6245be0cdbSDinh Nguyen 		/* This will release CPU #1 out of reset. */
6345be0cdbSDinh Nguyen 		writel(0, rst_manager_base_addr + SOCFPGA_A10_RSTMGR_MODMPURST);
649c4566a1SDinh Nguyen 	}
659c4566a1SDinh Nguyen 
6645be0cdbSDinh Nguyen 	return 0;
679c4566a1SDinh Nguyen }
689c4566a1SDinh Nguyen 
socfpga_smp_prepare_cpus(unsigned int max_cpus)699c4566a1SDinh Nguyen static void __init socfpga_smp_prepare_cpus(unsigned int max_cpus)
709c4566a1SDinh Nguyen {
71122694a0SDinh Nguyen 	struct device_node *np;
72122694a0SDinh Nguyen 	void __iomem *socfpga_scu_base_addr;
73122694a0SDinh Nguyen 
74122694a0SDinh Nguyen 	np = of_find_compatible_node(NULL, NULL, "arm,cortex-a9-scu");
75122694a0SDinh Nguyen 	if (!np) {
76122694a0SDinh Nguyen 		pr_err("%s: missing scu\n", __func__);
77122694a0SDinh Nguyen 		return;
78122694a0SDinh Nguyen 	}
79122694a0SDinh Nguyen 
80122694a0SDinh Nguyen 	socfpga_scu_base_addr = of_iomap(np, 0);
81122694a0SDinh Nguyen 	if (!socfpga_scu_base_addr)
82122694a0SDinh Nguyen 		return;
839c4566a1SDinh Nguyen 	scu_enable(socfpga_scu_base_addr);
849c4566a1SDinh Nguyen }
859c4566a1SDinh Nguyen 
865d37e80bSArnd Bergmann #ifdef CONFIG_HOTPLUG_CPU
879c4566a1SDinh Nguyen /*
889c4566a1SDinh Nguyen  * platform-specific code to shutdown a CPU
899c4566a1SDinh Nguyen  *
909c4566a1SDinh Nguyen  * Called with IRQs disabled
919c4566a1SDinh Nguyen  */
socfpga_cpu_die(unsigned int cpu)929c4566a1SDinh Nguyen static void socfpga_cpu_die(unsigned int cpu)
939c4566a1SDinh Nguyen {
94d686ce42SAlan Tull 	/* Do WFI. If we wake up early, go back into WFI */
95d686ce42SAlan Tull 	while (1)
969c4566a1SDinh Nguyen 		cpu_do_idle();
979c4566a1SDinh Nguyen }
989c4566a1SDinh Nguyen 
99b33612e1SHiraku Toyooka /*
100b33612e1SHiraku Toyooka  * We need a dummy function so that platform_can_cpu_hotplug() knows
101b33612e1SHiraku Toyooka  * we support CPU hotplug. However, the function does not need to do
102b33612e1SHiraku Toyooka  * anything, because CPUs going offline just do WFI. We could reset
103b33612e1SHiraku Toyooka  * the CPUs but it would increase power consumption.
104b33612e1SHiraku Toyooka  */
socfpga_cpu_kill(unsigned int cpu)105b33612e1SHiraku Toyooka static int socfpga_cpu_kill(unsigned int cpu)
106b33612e1SHiraku Toyooka {
107b33612e1SHiraku Toyooka 	return 1;
108b33612e1SHiraku Toyooka }
1095d37e80bSArnd Bergmann #endif
110b33612e1SHiraku Toyooka 
11175305275SMasahiro Yamada static const struct smp_operations socfpga_smp_ops __initconst = {
1129c4566a1SDinh Nguyen 	.smp_prepare_cpus	= socfpga_smp_prepare_cpus,
1139c4566a1SDinh Nguyen 	.smp_boot_secondary	= socfpga_boot_secondary,
1149c4566a1SDinh Nguyen #ifdef CONFIG_HOTPLUG_CPU
1159c4566a1SDinh Nguyen 	.cpu_die		= socfpga_cpu_die,
116b33612e1SHiraku Toyooka 	.cpu_kill		= socfpga_cpu_kill,
1179c4566a1SDinh Nguyen #endif
1189c4566a1SDinh Nguyen };
1195f763ef8SDinh Nguyen 
12075305275SMasahiro Yamada static const struct smp_operations socfpga_a10_smp_ops __initconst = {
12145be0cdbSDinh Nguyen 	.smp_prepare_cpus	= socfpga_smp_prepare_cpus,
12245be0cdbSDinh Nguyen 	.smp_boot_secondary	= socfpga_a10_boot_secondary,
12345be0cdbSDinh Nguyen #ifdef CONFIG_HOTPLUG_CPU
12445be0cdbSDinh Nguyen 	.cpu_die		= socfpga_cpu_die,
125b33612e1SHiraku Toyooka 	.cpu_kill		= socfpga_cpu_kill,
12645be0cdbSDinh Nguyen #endif
12745be0cdbSDinh Nguyen };
12845be0cdbSDinh Nguyen 
1295f763ef8SDinh Nguyen CPU_METHOD_OF_DECLARE(socfpga_smp, "altr,socfpga-smp", &socfpga_smp_ops);
13045be0cdbSDinh Nguyen CPU_METHOD_OF_DECLARE(socfpga_a10_smp, "altr,socfpga-a10-smp", &socfpga_a10_smp_ops);
131