aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-exynos4/platsmp.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-exynos4/platsmp.c')
-rw-r--r--arch/arm/mach-exynos4/platsmp.c77
1 files changed, 61 insertions, 16 deletions
diff --git a/arch/arm/mach-exynos4/platsmp.c b/arch/arm/mach-exynos4/platsmp.c
index c5e65a02be8..0c90896ad9a 100644
--- a/arch/arm/mach-exynos4/platsmp.c
+++ b/arch/arm/mach-exynos4/platsmp.c
@@ -28,9 +28,12 @@
28 28
29#include <mach/hardware.h> 29#include <mach/hardware.h>
30#include <mach/regs-clock.h> 30#include <mach/regs-clock.h>
31#include <mach/regs-pmu.h>
31 32
32extern void exynos4_secondary_startup(void); 33extern void exynos4_secondary_startup(void);
33 34
35#define CPU1_BOOT_REG S5P_VA_SYSRAM
36
34/* 37/*
35 * control for which core is the next to come out of the secondary 38 * control for which core is the next to come out of the secondary
36 * boot "holding pen" 39 * boot "holding pen"
@@ -58,6 +61,31 @@ static void __iomem *scu_base_addr(void)
58 61
59static DEFINE_SPINLOCK(boot_lock); 62static DEFINE_SPINLOCK(boot_lock);
60 63
64static void __cpuinit exynos4_gic_secondary_init(void)
65{
66 void __iomem *dist_base = S5P_VA_GIC_DIST +
67 (EXYNOS4_GIC_BANK_OFFSET * smp_processor_id());
68 void __iomem *cpu_base = S5P_VA_GIC_CPU +
69 (EXYNOS4_GIC_BANK_OFFSET * smp_processor_id());
70 int i;
71
72 /*
73 * Deal with the banked PPI and SGI interrupts - disable all
74 * PPI interrupts, ensure all SGI interrupts are enabled.
75 */
76 __raw_writel(0xffff0000, dist_base + GIC_DIST_ENABLE_CLEAR);
77 __raw_writel(0x0000ffff, dist_base + GIC_DIST_ENABLE_SET);
78
79 /*
80 * Set priority on PPI and SGI interrupts
81 */
82 for (i = 0; i < 32; i += 4)
83 __raw_writel(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4 / 4);
84
85 __raw_writel(0xf0, cpu_base + GIC_CPU_PRIMASK);
86 __raw_writel(1, cpu_base + GIC_CPU_CTRL);
87}
88
61void __cpuinit platform_secondary_init(unsigned int cpu) 89void __cpuinit platform_secondary_init(unsigned int cpu)
62{ 90{
63 /* 91 /*
@@ -65,7 +93,7 @@ void __cpuinit platform_secondary_init(unsigned int cpu)
65 * core (e.g. timer irq), then they will not have been enabled 93 * core (e.g. timer irq), then they will not have been enabled
66 * for us: do so 94 * for us: do so
67 */ 95 */
68 gic_secondary_init(0); 96 exynos4_gic_secondary_init();
69 97
70 /* 98 /*
71 * let the primary processor know we're out of the 99 * let the primary processor know we're out of the
@@ -78,6 +106,8 @@ void __cpuinit platform_secondary_init(unsigned int cpu)
78 */ 106 */
79 spin_lock(&boot_lock); 107 spin_lock(&boot_lock);
80 spin_unlock(&boot_lock); 108 spin_unlock(&boot_lock);
109
110 set_cpu_online(cpu, true);
81} 111}
82 112
83int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) 113int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
@@ -100,16 +130,41 @@ int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle)
100 */ 130 */
101 write_pen_release(cpu); 131 write_pen_release(cpu);
102 132
133 if (!(__raw_readl(S5P_ARM_CORE1_STATUS) & S5P_CORE_LOCAL_PWR_EN)) {
134 __raw_writel(S5P_CORE_LOCAL_PWR_EN,
135 S5P_ARM_CORE1_CONFIGURATION);
136
137 timeout = 10;
138
139 /* wait max 10 ms until cpu1 is on */
140 while ((__raw_readl(S5P_ARM_CORE1_STATUS)
141 & S5P_CORE_LOCAL_PWR_EN) != S5P_CORE_LOCAL_PWR_EN) {
142 if (timeout-- == 0)
143 break;
144
145 mdelay(1);
146 }
147
148 if (timeout == 0) {
149 printk(KERN_ERR "cpu1 power enable failed");
150 spin_unlock(&boot_lock);
151 return -ETIMEDOUT;
152 }
153 }
103 /* 154 /*
104 * Send the secondary CPU a soft interrupt, thereby causing 155 * Send the secondary CPU a soft interrupt, thereby causing
105 * the boot monitor to read the system wide flags register, 156 * the boot monitor to read the system wide flags register,
106 * and branch to the address found there. 157 * and branch to the address found there.
107 */ 158 */
108 gic_raise_softirq(cpumask_of(cpu), 1);
109 159
110 timeout = jiffies + (1 * HZ); 160 timeout = jiffies + (1 * HZ);
111 while (time_before(jiffies, timeout)) { 161 while (time_before(jiffies, timeout)) {
112 smp_rmb(); 162 smp_rmb();
163
164 __raw_writel(BSYM(virt_to_phys(exynos4_secondary_startup)),
165 CPU1_BOOT_REG);
166 gic_raise_softirq(cpumask_of(cpu), 1);
167
113 if (pen_release == -1) 168 if (pen_release == -1)
114 break; 169 break;
115 170
@@ -138,12 +193,10 @@ void __init smp_init_cpus(void)
138 ncores = scu_base ? scu_get_core_count(scu_base) : 1; 193 ncores = scu_base ? scu_get_core_count(scu_base) : 1;
139 194
140 /* sanity check */ 195 /* sanity check */
141 if (ncores > NR_CPUS) { 196 if (ncores > nr_cpu_ids) {
142 printk(KERN_WARNING 197 pr_warn("SMP: %u cores greater than maximum (%u), clipping\n",
143 "EXYNOS4: no. of cores (%d) greater than configured " 198 ncores, nr_cpu_ids);
144 "maximum of %d - clipping\n", 199 ncores = nr_cpu_ids;
145 ncores, NR_CPUS);
146 ncores = NR_CPUS;
147 } 200 }
148 201
149 for (i = 0; i < ncores; i++) 202 for (i = 0; i < ncores; i++)
@@ -154,14 +207,6 @@ void __init smp_init_cpus(void)
154 207
155void __init platform_smp_prepare_cpus(unsigned int max_cpus) 208void __init platform_smp_prepare_cpus(unsigned int max_cpus)
156{ 209{
157 int i;
158
159 /*
160 * Initialise the present map, which describes the set of CPUs
161 * actually populated at the present time.
162 */
163 for (i = 0; i < max_cpus; i++)
164 set_cpu_present(i, true);
165 210
166 scu_enable(scu_base_addr()); 211 scu_enable(scu_base_addr());
167 212