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