1 /* 2 * Symmetric Multi Processing (SMP) support for Marvell EBU Cortex-A9 3 * based SOCs (Armada 375/38x). 4 * 5 * Copyright (C) 2014 Marvell 6 * 7 * Gregory CLEMENT <gregory.clement@free-electrons.com> 8 * Thomas Petazzoni <thomas.petazzoni@free-electrons.com> 9 * 10 * This file is licensed under the terms of the GNU General Public 11 * License version 2. This program is licensed "as is" without any 12 * warranty of any kind, whether express or implied. 13 */ 14 15 #include <linux/init.h> 16 #include <linux/io.h> 17 #include <linux/of.h> 18 #include <linux/smp.h> 19 #include <linux/mbus.h> 20 #include <asm/smp_scu.h> 21 #include <asm/smp_plat.h> 22 #include "common.h" 23 #include "mvebu-soc-id.h" 24 #include "pmsu.h" 25 26 #define CRYPT0_ENG_ID 41 27 #define CRYPT0_ENG_ATTR 0x1 28 #define SRAM_PHYS_BASE 0xFFFF0000 29 30 #define BOOTROM_BASE 0xFFF00000 31 #define BOOTROM_SIZE 0x100000 32 33 extern unsigned char armada_375_smp_cpu1_enable_code_end; 34 extern unsigned char armada_375_smp_cpu1_enable_code_start; 35 36 void armada_375_smp_cpu1_enable_wa(void) 37 { 38 void __iomem *sram_virt_base; 39 40 mvebu_mbus_del_window(BOOTROM_BASE, BOOTROM_SIZE); 41 mvebu_mbus_add_window_by_id(CRYPT0_ENG_ID, CRYPT0_ENG_ATTR, 42 SRAM_PHYS_BASE, SZ_64K); 43 sram_virt_base = ioremap(SRAM_PHYS_BASE, SZ_64K); 44 45 memcpy(sram_virt_base, &armada_375_smp_cpu1_enable_code_start, 46 &armada_375_smp_cpu1_enable_code_end 47 - &armada_375_smp_cpu1_enable_code_start); 48 } 49 50 extern void mvebu_cortex_a9_secondary_startup(void); 51 52 static int __cpuinit mvebu_cortex_a9_boot_secondary(unsigned int cpu, 53 struct task_struct *idle) 54 { 55 int ret, hw_cpu; 56 57 pr_info("Booting CPU %d\n", cpu); 58 59 /* 60 * Write the address of secondary startup into the system-wide 61 * flags register. The boot monitor waits until it receives a 62 * soft interrupt, and then the secondary CPU branches to this 63 * address. 64 */ 65 hw_cpu = cpu_logical_map(cpu); 66 67 if (of_machine_is_compatible("marvell,armada375")) { 68 u32 dev, rev; 69 70 if (mvebu_get_soc_id(&dev, &rev) == 0 && 71 rev == ARMADA_375_Z1_REV) 72 armada_375_smp_cpu1_enable_wa(); 73 74 mvebu_system_controller_set_cpu_boot_addr(mvebu_cortex_a9_secondary_startup); 75 } 76 else { 77 mvebu_pmsu_set_cpu_boot_addr(hw_cpu, 78 mvebu_cortex_a9_secondary_startup); 79 } 80 81 smp_wmb(); 82 ret = mvebu_cpu_reset_deassert(hw_cpu); 83 if (ret) { 84 pr_err("Could not start the secondary CPU: %d\n", ret); 85 return ret; 86 } 87 arch_send_wakeup_ipi_mask(cpumask_of(cpu)); 88 89 return 0; 90 } 91 92 static struct smp_operations mvebu_cortex_a9_smp_ops __initdata = { 93 .smp_boot_secondary = mvebu_cortex_a9_boot_secondary, 94 #ifdef CONFIG_HOTPLUG_CPU 95 .cpu_die = armada_xp_cpu_die, 96 #endif 97 }; 98 99 CPU_METHOD_OF_DECLARE(mvebu_armada_375_smp, "marvell,armada-375-smp", 100 &mvebu_cortex_a9_smp_ops); 101 CPU_METHOD_OF_DECLARE(mvebu_armada_380_smp, "marvell,armada-380-smp", 102 &mvebu_cortex_a9_smp_ops); 103