xref: /openbmc/linux/arch/arm/mach-mvebu/platsmp-a9.c (revision 87384cc0b4bffbe26d9172d49d8b287332e9d397)
11ee89e22SGregory CLEMENT /*
21ee89e22SGregory CLEMENT  * Symmetric Multi Processing (SMP) support for Marvell EBU Cortex-A9
31ee89e22SGregory CLEMENT  * based SOCs (Armada 375/38x).
41ee89e22SGregory CLEMENT  *
51ee89e22SGregory CLEMENT  * Copyright (C) 2014 Marvell
61ee89e22SGregory CLEMENT  *
71ee89e22SGregory CLEMENT  * Gregory CLEMENT <gregory.clement@free-electrons.com>
81ee89e22SGregory CLEMENT  * Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
91ee89e22SGregory CLEMENT  *
101ee89e22SGregory CLEMENT  * This file is licensed under the terms of the GNU General Public
111ee89e22SGregory CLEMENT  * License version 2.  This program is licensed "as is" without any
121ee89e22SGregory CLEMENT  * warranty of any kind, whether express or implied.
131ee89e22SGregory CLEMENT  */
141ee89e22SGregory CLEMENT 
151ee89e22SGregory CLEMENT #include <linux/init.h>
161ee89e22SGregory CLEMENT #include <linux/io.h>
171ee89e22SGregory CLEMENT #include <linux/of.h>
181ee89e22SGregory CLEMENT #include <linux/smp.h>
19*87384cc0SGregory CLEMENT #include <linux/mbus.h>
201ee89e22SGregory CLEMENT #include <asm/smp_scu.h>
211ee89e22SGregory CLEMENT #include <asm/smp_plat.h>
221ee89e22SGregory CLEMENT #include "common.h"
231ee89e22SGregory CLEMENT #include "pmsu.h"
241ee89e22SGregory CLEMENT 
25*87384cc0SGregory CLEMENT #define CRYPT0_ENG_ID   41
26*87384cc0SGregory CLEMENT #define CRYPT0_ENG_ATTR 0x1
27*87384cc0SGregory CLEMENT #define SRAM_PHYS_BASE  0xFFFF0000
28*87384cc0SGregory CLEMENT 
29*87384cc0SGregory CLEMENT #define BOOTROM_BASE    0xFFF00000
30*87384cc0SGregory CLEMENT #define BOOTROM_SIZE    0x100000
31*87384cc0SGregory CLEMENT 
32*87384cc0SGregory CLEMENT extern unsigned char armada_375_smp_cpu1_enable_code_end;
33*87384cc0SGregory CLEMENT extern unsigned char armada_375_smp_cpu1_enable_code_start;
34*87384cc0SGregory CLEMENT 
35*87384cc0SGregory CLEMENT void armada_375_smp_cpu1_enable_wa(void)
36*87384cc0SGregory CLEMENT {
37*87384cc0SGregory CLEMENT 	void __iomem *sram_virt_base;
38*87384cc0SGregory CLEMENT 
39*87384cc0SGregory CLEMENT 	mvebu_mbus_del_window(BOOTROM_BASE, BOOTROM_SIZE);
40*87384cc0SGregory CLEMENT 	mvebu_mbus_add_window_by_id(CRYPT0_ENG_ID, CRYPT0_ENG_ATTR,
41*87384cc0SGregory CLEMENT 				SRAM_PHYS_BASE, SZ_64K);
42*87384cc0SGregory CLEMENT 	sram_virt_base = ioremap(SRAM_PHYS_BASE, SZ_64K);
43*87384cc0SGregory CLEMENT 
44*87384cc0SGregory CLEMENT 	memcpy(sram_virt_base, &armada_375_smp_cpu1_enable_code_start,
45*87384cc0SGregory CLEMENT 	       &armada_375_smp_cpu1_enable_code_end
46*87384cc0SGregory CLEMENT 	       - &armada_375_smp_cpu1_enable_code_start);
47*87384cc0SGregory CLEMENT }
48*87384cc0SGregory CLEMENT 
491ee89e22SGregory CLEMENT extern void mvebu_cortex_a9_secondary_startup(void);
501ee89e22SGregory CLEMENT 
511ee89e22SGregory CLEMENT static int __cpuinit mvebu_cortex_a9_boot_secondary(unsigned int cpu,
521ee89e22SGregory CLEMENT 						    struct task_struct *idle)
531ee89e22SGregory CLEMENT {
541ee89e22SGregory CLEMENT 	int ret, hw_cpu;
551ee89e22SGregory CLEMENT 
561ee89e22SGregory CLEMENT 	pr_info("Booting CPU %d\n", cpu);
571ee89e22SGregory CLEMENT 
581ee89e22SGregory CLEMENT 	/*
591ee89e22SGregory CLEMENT 	 * Write the address of secondary startup into the system-wide
601ee89e22SGregory CLEMENT 	 * flags register. The boot monitor waits until it receives a
611ee89e22SGregory CLEMENT 	 * soft interrupt, and then the secondary CPU branches to this
621ee89e22SGregory CLEMENT 	 * address.
631ee89e22SGregory CLEMENT 	 */
641ee89e22SGregory CLEMENT 	hw_cpu = cpu_logical_map(cpu);
651ee89e22SGregory CLEMENT 
661ee89e22SGregory CLEMENT 	if (of_machine_is_compatible("marvell,armada375"))
671ee89e22SGregory CLEMENT 		mvebu_system_controller_set_cpu_boot_addr(mvebu_cortex_a9_secondary_startup);
681ee89e22SGregory CLEMENT 	else
691ee89e22SGregory CLEMENT 		mvebu_pmsu_set_cpu_boot_addr(hw_cpu,
701ee89e22SGregory CLEMENT 					     mvebu_cortex_a9_secondary_startup);
711ee89e22SGregory CLEMENT 
721ee89e22SGregory CLEMENT 	smp_wmb();
731ee89e22SGregory CLEMENT 	ret = mvebu_cpu_reset_deassert(hw_cpu);
741ee89e22SGregory CLEMENT 	if (ret) {
751ee89e22SGregory CLEMENT 		pr_err("Could not start the secondary CPU: %d\n", ret);
761ee89e22SGregory CLEMENT 		return ret;
771ee89e22SGregory CLEMENT 	}
781ee89e22SGregory CLEMENT 	arch_send_wakeup_ipi_mask(cpumask_of(cpu));
791ee89e22SGregory CLEMENT 
801ee89e22SGregory CLEMENT 	return 0;
811ee89e22SGregory CLEMENT }
821ee89e22SGregory CLEMENT 
83*87384cc0SGregory CLEMENT static void __init mvebu_cortex_a9_smp_prepare_cpus(unsigned int max_cpus)
84*87384cc0SGregory CLEMENT {
85*87384cc0SGregory CLEMENT 	if (of_machine_is_compatible("marvell,armada375"))
86*87384cc0SGregory CLEMENT 		armada_375_smp_cpu1_enable_wa();
87*87384cc0SGregory CLEMENT }
88*87384cc0SGregory CLEMENT 
891ee89e22SGregory CLEMENT static struct smp_operations mvebu_cortex_a9_smp_ops __initdata = {
90*87384cc0SGregory CLEMENT 	.smp_prepare_cpus	= mvebu_cortex_a9_smp_prepare_cpus,
911ee89e22SGregory CLEMENT 	.smp_boot_secondary	= mvebu_cortex_a9_boot_secondary,
921ee89e22SGregory CLEMENT #ifdef CONFIG_HOTPLUG_CPU
931ee89e22SGregory CLEMENT 	.cpu_die		= armada_xp_cpu_die,
941ee89e22SGregory CLEMENT #endif
951ee89e22SGregory CLEMENT };
961ee89e22SGregory CLEMENT 
971ee89e22SGregory CLEMENT CPU_METHOD_OF_DECLARE(mvebu_armada_375_smp, "marvell,armada-375-smp",
981ee89e22SGregory CLEMENT 		      &mvebu_cortex_a9_smp_ops);
991ee89e22SGregory CLEMENT CPU_METHOD_OF_DECLARE(mvebu_armada_380_smp, "marvell,armada-380-smp",
1001ee89e22SGregory CLEMENT 		      &mvebu_cortex_a9_smp_ops);
101