diff options
Diffstat (limited to 'arch/arm/mach-exynos4/platsmp.c')
-rw-r--r-- | arch/arm/mach-exynos4/platsmp.c | 65 |
1 files changed, 55 insertions, 10 deletions
diff --git a/arch/arm/mach-exynos4/platsmp.c b/arch/arm/mach-exynos4/platsmp.c index c5e65a02be8..7c2282c6ba8 100644 --- a/arch/arm/mach-exynos4/platsmp.c +++ b/arch/arm/mach-exynos4/platsmp.c @@ -28,9 +28,12 @@ #include <mach/hardware.h> #include <mach/regs-clock.h> +#include <mach/regs-pmu.h> extern void exynos4_secondary_startup(void); +#define CPU1_BOOT_REG S5P_VA_SYSRAM + /* * control for which core is the next to come out of the secondary * boot "holding pen" @@ -58,6 +61,31 @@ static void __iomem *scu_base_addr(void) static DEFINE_SPINLOCK(boot_lock); +static void __cpuinit exynos4_gic_secondary_init(void) +{ + void __iomem *dist_base = S5P_VA_GIC_DIST + + (EXYNOS4_GIC_BANK_OFFSET * smp_processor_id()); + void __iomem *cpu_base = S5P_VA_GIC_CPU + + (EXYNOS4_GIC_BANK_OFFSET * smp_processor_id()); + int i; + + /* + * Deal with the banked PPI and SGI interrupts - disable all + * PPI interrupts, ensure all SGI interrupts are enabled. + */ + __raw_writel(0xffff0000, dist_base + GIC_DIST_ENABLE_CLEAR); + __raw_writel(0x0000ffff, dist_base + GIC_DIST_ENABLE_SET); + + /* + * Set priority on PPI and SGI interrupts + */ + for (i = 0; i < 32; i += 4) + __raw_writel(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4 / 4); + + __raw_writel(0xf0, cpu_base + GIC_CPU_PRIMASK); + __raw_writel(1, cpu_base + GIC_CPU_CTRL); +} + void __cpuinit platform_secondary_init(unsigned int cpu) { /* @@ -65,7 +93,7 @@ void __cpuinit platform_secondary_init(unsigned int cpu) * core (e.g. timer irq), then they will not have been enabled * for us: do so */ - gic_secondary_init(0); + exynos4_gic_secondary_init(); /* * let the primary processor know we're out of the @@ -100,16 +128,41 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) */ write_pen_release(cpu); + if (!(__raw_readl(S5P_ARM_CORE1_STATUS) & S5P_CORE_LOCAL_PWR_EN)) { + __raw_writel(S5P_CORE_LOCAL_PWR_EN, + S5P_ARM_CORE1_CONFIGURATION); + + timeout = 10; + + /* wait max 10 ms until cpu1 is on */ + while ((__raw_readl(S5P_ARM_CORE1_STATUS) + & S5P_CORE_LOCAL_PWR_EN) != S5P_CORE_LOCAL_PWR_EN) { + if (timeout-- == 0) + break; + + mdelay(1); + } + + if (timeout == 0) { + printk(KERN_ERR "cpu1 power enable failed"); + spin_unlock(&boot_lock); + return -ETIMEDOUT; + } + } /* * Send the secondary CPU a soft interrupt, thereby causing * the boot monitor to read the system wide flags register, * and branch to the address found there. */ - gic_raise_softirq(cpumask_of(cpu), 1); timeout = jiffies + (1 * HZ); while (time_before(jiffies, timeout)) { smp_rmb(); + + __raw_writel(BSYM(virt_to_phys(exynos4_secondary_startup)), + CPU1_BOOT_REG); + gic_raise_softirq(cpumask_of(cpu), 1); + if (pen_release == -1) break; @@ -154,14 +207,6 @@ void __init smp_init_cpus(void) void __init platform_smp_prepare_cpus(unsigned int max_cpus) { - int i; - - /* - * Initialise the present map, which describes the set of CPUs - * actually populated at the present time. - */ - for (i = 0; i < max_cpus; i++) - set_cpu_present(i, true); scu_enable(scu_base_addr()); |