a58d5af7d9
The Armada 375 SMP workaround only needs to be applied to the Z1 revision of the SoC. The A0 and later revisions have been fixed, and no longer need this workaround. Note that the initialization of the SMP workaround is delayed from ->smp_prepare_cpus() to ->smp_boot_secondary() because when ->smp_prepare_cpus() is called, the early initcalls have not be called, so the mvebu-soc-id mechanism is not operational. Since the workaround is anyway not needed before the secondary CPU is started, we can delay its implementation until the ->smp_boot_secondary() call. Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> Link: https://lkml.kernel.org/r/1399302326-6917-5-git-send-email-thomas.petazzoni@free-electrons.com Signed-off-by: Jason Cooper <jason@lakedaemon.net>
102 lines
2.8 KiB
C
102 lines
2.8 KiB
C
/*
|
|
* Symmetric Multi Processing (SMP) support for Marvell EBU Cortex-A9
|
|
* based SOCs (Armada 375/38x).
|
|
*
|
|
* Copyright (C) 2014 Marvell
|
|
*
|
|
* Gregory CLEMENT <gregory.clement@free-electrons.com>
|
|
* Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
|
|
*
|
|
* This file is licensed under the terms of the GNU General Public
|
|
* License version 2. This program is licensed "as is" without any
|
|
* warranty of any kind, whether express or implied.
|
|
*/
|
|
|
|
#include <linux/init.h>
|
|
#include <linux/io.h>
|
|
#include <linux/of.h>
|
|
#include <linux/smp.h>
|
|
#include <linux/mbus.h>
|
|
#include <asm/smp_scu.h>
|
|
#include <asm/smp_plat.h>
|
|
#include "common.h"
|
|
#include "mvebu-soc-id.h"
|
|
#include "pmsu.h"
|
|
|
|
#define CRYPT0_ENG_ID 41
|
|
#define CRYPT0_ENG_ATTR 0x1
|
|
#define SRAM_PHYS_BASE 0xFFFF0000
|
|
|
|
#define BOOTROM_BASE 0xFFF00000
|
|
#define BOOTROM_SIZE 0x100000
|
|
|
|
extern unsigned char armada_375_smp_cpu1_enable_code_end;
|
|
extern unsigned char armada_375_smp_cpu1_enable_code_start;
|
|
|
|
void armada_375_smp_cpu1_enable_wa(void)
|
|
{
|
|
void __iomem *sram_virt_base;
|
|
|
|
mvebu_mbus_del_window(BOOTROM_BASE, BOOTROM_SIZE);
|
|
mvebu_mbus_add_window_by_id(CRYPT0_ENG_ID, CRYPT0_ENG_ATTR,
|
|
SRAM_PHYS_BASE, SZ_64K);
|
|
sram_virt_base = ioremap(SRAM_PHYS_BASE, SZ_64K);
|
|
|
|
memcpy(sram_virt_base, &armada_375_smp_cpu1_enable_code_start,
|
|
&armada_375_smp_cpu1_enable_code_end
|
|
- &armada_375_smp_cpu1_enable_code_start);
|
|
}
|
|
|
|
extern void mvebu_cortex_a9_secondary_startup(void);
|
|
|
|
static int __cpuinit mvebu_cortex_a9_boot_secondary(unsigned int cpu,
|
|
struct task_struct *idle)
|
|
{
|
|
int ret, hw_cpu;
|
|
|
|
pr_info("Booting CPU %d\n", cpu);
|
|
|
|
/*
|
|
* Write the address of secondary startup into the system-wide
|
|
* flags register. The boot monitor waits until it receives a
|
|
* soft interrupt, and then the secondary CPU branches to this
|
|
* address.
|
|
*/
|
|
hw_cpu = cpu_logical_map(cpu);
|
|
|
|
if (of_machine_is_compatible("marvell,armada375")) {
|
|
u32 dev, rev;
|
|
|
|
if (mvebu_get_soc_id(&dev, &rev) == 0 &&
|
|
rev == ARMADA_375_Z1_REV)
|
|
armada_375_smp_cpu1_enable_wa();
|
|
|
|
mvebu_system_controller_set_cpu_boot_addr(mvebu_cortex_a9_secondary_startup);
|
|
}
|
|
else {
|
|
mvebu_pmsu_set_cpu_boot_addr(hw_cpu,
|
|
mvebu_cortex_a9_secondary_startup);
|
|
}
|
|
|
|
smp_wmb();
|
|
ret = mvebu_cpu_reset_deassert(hw_cpu);
|
|
if (ret) {
|
|
pr_err("Could not start the secondary CPU: %d\n", ret);
|
|
return ret;
|
|
}
|
|
arch_send_wakeup_ipi_mask(cpumask_of(cpu));
|
|
|
|
return 0;
|
|
}
|
|
|
|
static struct smp_operations mvebu_cortex_a9_smp_ops __initdata = {
|
|
.smp_boot_secondary = mvebu_cortex_a9_boot_secondary,
|
|
#ifdef CONFIG_HOTPLUG_CPU
|
|
.cpu_die = armada_xp_cpu_die,
|
|
#endif
|
|
};
|
|
|
|
CPU_METHOD_OF_DECLARE(mvebu_armada_375_smp, "marvell,armada-375-smp",
|
|
&mvebu_cortex_a9_smp_ops);
|
|
CPU_METHOD_OF_DECLARE(mvebu_armada_380_smp, "marvell,armada-380-smp",
|
|
&mvebu_cortex_a9_smp_ops);
|