diff options
Diffstat (limited to 'arch/arm/mach-exynos4/platsmp.c')
-rw-r--r-- | arch/arm/mach-exynos4/platsmp.c | 77 |
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 | ||
32 | extern void exynos4_secondary_startup(void); | 33 | extern 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 | ||
59 | static DEFINE_SPINLOCK(boot_lock); | 62 | static DEFINE_SPINLOCK(boot_lock); |
60 | 63 | ||
64 | static 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 | |||
61 | void __cpuinit platform_secondary_init(unsigned int cpu) | 89 | void __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 | ||
83 | int __cpuinit boot_secondary(unsigned int cpu, struct task_struct *idle) | 113 | int __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 | ||
155 | void __init platform_smp_prepare_cpus(unsigned int max_cpus) | 208 | void __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 | ||