blob: f31e5782ca1c3c8569f0fda59c5aef16de07a94e [file] [log] [blame]
#include <linux/smp.h>
#include <linux/io.h>
#include <mach/hardware.h>
#include <asm/cacheflush.h>
#include <asm/smp_scu.h>
#include <asm/unified.h>
#include <linux/delay.h>
#include "common.h"
#define JUMP_TO_KERNEL_START_1 0xe3a00020 /* mov r0, #32 */
#define JUMP_TO_KERNEL_START_2 0xe590f000 /* ldr pc, [r0] */
/* SCU base address */
static void __iomem *scu_base;
static DEFINE_SPINLOCK(boot_lock);
void __iomem *ls1024a_get_scu_base(void)
{
return scu_base;
}
/*
* Initialise the CPU possible map early - this describes the CPUs
* which may be present or become present in the system.
*/
static void __init ls1024a_smp_init_cpus(void)
{
int i, ncores;
scu_base = (void *) COMCERTO_SCU_VADDR;
ncores = scu_get_core_count(scu_base);
/* sanity check */
if (ncores > nr_cpu_ids) {
pr_warn("SMP: %u cores greater than maximum (%u), clipping\n",
ncores, nr_cpu_ids);
ncores = nr_cpu_ids;
}
for (i = 0; i < ncores; i++)
set_cpu_possible(i, true);
}
static void __init ls1024a_smp_prepare_cpus(unsigned int max_cpus)
{
scu_enable(scu_base);
}
static int ls1024a_boot_secondary(unsigned int cpu, struct task_struct *idle)
{
/*
* Set synchronisation state between this boot processor
* and the secondary one
*/
spin_lock(&boot_lock);
/*
* Install the comcerto_secondary_startup pointer at 0x20
* Physical Address
*/
__raw_writel(virt_to_phys(ls1024a_secondary_startup), phys_to_virt(0x20));
__raw_writel((unsigned int)JUMP_TO_KERNEL_START_1 , phys_to_virt(0x00));
__raw_writel((unsigned int)JUMP_TO_KERNEL_START_2 , phys_to_virt(0x04));
smp_wmb();
__cpuc_flush_dcache_area((void *)phys_to_virt(0x00), 0x24);
outer_clean_range(__pa(phys_to_virt(0x00)), __pa(phys_to_virt(0x24)));
/* Get CPU 1 out of reset */
__raw_writel((__raw_readl(APB_VADDR(A9DP_CPU_RESET)) & ~CPU1_RST), APB_VADDR(A9DP_CPU_RESET));
__raw_writel((__raw_readl(APB_VADDR(A9DP_PWR_CNTRL)) & ~CLAMP_CORE1), APB_VADDR(A9DP_PWR_CNTRL));
__raw_writel((__raw_readl(APB_VADDR(A9DP_CPU_CLK_CNTRL)) | CPU1_CLK_ENABLE), APB_VADDR(A9DP_CPU_CLK_CNTRL));
#ifdef CONFIG_NEON
/* Get NEON 1 out of reset */
__raw_writel((__raw_readl(APB_VADDR(A9DP_CPU_RESET)) & ~NEON1_RST), APB_VADDR(A9DP_CPU_RESET));
__raw_writel((__raw_readl(APB_VADDR(A9DP_CPU_CLK_CNTRL)) | NEON1_CLK_ENABLE), APB_VADDR(A9DP_CPU_CLK_CNTRL));
#endif
/*
* Now the secondary core is starting up let it run its
* calibrations, then wait for it to finish
*/
spin_unlock(&boot_lock);
return 0;
}
struct smp_operations ls1024a_smp_ops __initdata = {
.smp_init_cpus = ls1024a_smp_init_cpus,
.smp_prepare_cpus = ls1024a_smp_prepare_cpus,
//.smp_secondary_init = ls1024a_secondary_init,
.smp_boot_secondary = ls1024a_boot_secondary,
#if 0
#ifdef CONFIG_HOTPLUG_CPU
.cpu_die = ls1024a_cpu_die,
#endif
#endif
};
CPU_METHOD_OF_DECLARE(fsl_ls1024a_smp, "fsl,ls1024a-smp", &ls1024a_smp_ops);