Commit | Line | Data |
---|---|---|
c51b4488 | 1 | /* |
96f1050d RG |
2 | * Copyright 2007-2009 Analog Devices Inc. |
3 | * Philippe Gerum <rpm@xenomai.org> | |
c51b4488 | 4 | * |
96f1050d | 5 | * Licensed under the GPL-2 or later. |
c51b4488 GY |
6 | */ |
7 | ||
8 | #include <linux/init.h> | |
9 | #include <linux/kernel.h> | |
10 | #include <linux/sched.h> | |
11 | #include <linux/delay.h> | |
12 | #include <asm/smp.h> | |
13 | #include <asm/dma.h> | |
0d152c27 | 14 | #include <asm/time.h> |
c51b4488 | 15 | |
c51b4488 GY |
16 | static DEFINE_SPINLOCK(boot_lock); |
17 | ||
c51b4488 GY |
18 | /* |
19 | * platform_init_cpus() - Tell the world about how many cores we | |
20 | * have. This is called while setting up the architecture support | |
21 | * (setup_arch()), so don't be too demanding here with respect to | |
22 | * available kernel services. | |
23 | */ | |
24 | ||
25 | void __init platform_init_cpus(void) | |
26 | { | |
3cb8a39f KM |
27 | struct cpumask mask; |
28 | ||
29 | cpumask_set_cpu(0, &mask); /* CoreA */ | |
30 | cpumask_set_cpu(1, &mask); /* CoreB */ | |
31 | init_cpu_possible(&mask); | |
c51b4488 GY |
32 | } |
33 | ||
34 | void __init platform_prepare_cpus(unsigned int max_cpus) | |
35 | { | |
3cb8a39f KM |
36 | struct cpumask mask; |
37 | ||
c6345ab1 | 38 | bfin_relocate_coreb_l1_mem(); |
c51b4488 GY |
39 | |
40 | /* Both cores ought to be present on a bf561! */ | |
3cb8a39f KM |
41 | cpumask_set_cpu(0, &mask); /* CoreA */ |
42 | cpumask_set_cpu(1, &mask); /* CoreB */ | |
43 | init_cpu_present(&mask); | |
c51b4488 GY |
44 | } |
45 | ||
46 | int __init setup_profiling_timer(unsigned int multiplier) /* not supported */ | |
47 | { | |
48 | return -EINVAL; | |
49 | } | |
50 | ||
51 | void __cpuinit platform_secondary_init(unsigned int cpu) | |
52 | { | |
c51b4488 | 53 | /* Clone setup for peripheral interrupt sources from CoreA. */ |
39c99969 MF |
54 | bfin_write_SICB_IMASK0(bfin_read_SIC_IMASK0()); |
55 | bfin_write_SICB_IMASK1(bfin_read_SIC_IMASK1()); | |
c51b4488 GY |
56 | SSYNC(); |
57 | ||
58 | /* Clone setup for IARs from CoreA. */ | |
39c99969 MF |
59 | bfin_write_SICB_IAR0(bfin_read_SIC_IAR0()); |
60 | bfin_write_SICB_IAR1(bfin_read_SIC_IAR1()); | |
61 | bfin_write_SICB_IAR2(bfin_read_SIC_IAR2()); | |
62 | bfin_write_SICB_IAR3(bfin_read_SIC_IAR3()); | |
63 | bfin_write_SICB_IAR4(bfin_read_SIC_IAR4()); | |
64 | bfin_write_SICB_IAR5(bfin_read_SIC_IAR5()); | |
65 | bfin_write_SICB_IAR6(bfin_read_SIC_IAR6()); | |
66 | bfin_write_SICB_IAR7(bfin_read_SIC_IAR7()); | |
0b39db28 GY |
67 | bfin_write_SICB_IWR0(IWR_DISABLE_ALL); |
68 | bfin_write_SICB_IWR1(IWR_DISABLE_ALL); | |
c51b4488 GY |
69 | SSYNC(); |
70 | ||
c51b4488 | 71 | /* We are done with local CPU inits, unblock the boot CPU. */ |
682f5dc4 | 72 | set_cpu_online(cpu, true); |
c51b4488 GY |
73 | spin_lock(&boot_lock); |
74 | spin_unlock(&boot_lock); | |
75 | } | |
76 | ||
77 | int __cpuinit platform_boot_secondary(unsigned int cpu, struct task_struct *idle) | |
78 | { | |
79 | unsigned long timeout; | |
80 | ||
c51b4488 GY |
81 | printk(KERN_INFO "Booting Core B.\n"); |
82 | ||
83 | spin_lock(&boot_lock); | |
84 | ||
94a038c2 | 85 | if ((bfin_read_SYSCR() & COREB_SRAM_INIT) == 0) { |
0b39db28 | 86 | /* CoreB already running, sending ipi to wakeup it */ |
d0014be4 | 87 | smp_send_reschedule(cpu); |
0b39db28 GY |
88 | } else { |
89 | /* Kick CoreB, which should start execution from CORE_SRAM_BASE. */ | |
94a038c2 | 90 | bfin_write_SYSCR(bfin_read_SYSCR() & ~COREB_SRAM_INIT); |
0b39db28 GY |
91 | SSYNC(); |
92 | } | |
c51b4488 GY |
93 | |
94 | timeout = jiffies + 1 * HZ; | |
95 | while (time_before(jiffies, timeout)) { | |
682f5dc4 | 96 | if (cpu_online(cpu)) |
c51b4488 GY |
97 | break; |
98 | udelay(100); | |
99 | barrier(); | |
100 | } | |
101 | ||
682f5dc4 | 102 | if (cpu_online(cpu)) { |
578d36f5 YL |
103 | /* release the lock and let coreb run */ |
104 | spin_unlock(&boot_lock); | |
105 | return 0; | |
106 | } else | |
107 | panic("CPU%u: processor failed to boot\n", cpu); | |
c51b4488 GY |
108 | } |
109 | ||
73a40064 YL |
110 | static const char supple0[] = "IRQ_SUPPLE_0"; |
111 | static const char supple1[] = "IRQ_SUPPLE_1"; | |
112 | void __init platform_request_ipi(int irq, void *handler) | |
c51b4488 GY |
113 | { |
114 | int ret; | |
73a40064 | 115 | const char *name = (irq == IRQ_SUPPLE_0) ? supple0 : supple1; |
c51b4488 | 116 | |
16df3666 BL |
117 | ret = request_irq(irq, handler, IRQF_PERCPU | IRQF_NO_SUSPEND | |
118 | IRQF_FORCE_RESUME, name, handler); | |
c51b4488 | 119 | if (ret) |
73a40064 | 120 | panic("Cannot request %s for IPI service", name); |
c51b4488 GY |
121 | } |
122 | ||
73a40064 | 123 | void platform_send_ipi(cpumask_t callmap, int irq) |
c51b4488 GY |
124 | { |
125 | unsigned int cpu; | |
73a40064 | 126 | int offset = (irq == IRQ_SUPPLE_0) ? 6 : 8; |
c51b4488 GY |
127 | |
128 | for_each_cpu_mask(cpu, callmap) { | |
129 | BUG_ON(cpu >= 2); | |
130 | SSYNC(); | |
73a40064 | 131 | bfin_write_SICB_SYSCR(bfin_read_SICB_SYSCR() | (1 << (offset + cpu))); |
c51b4488 GY |
132 | SSYNC(); |
133 | } | |
134 | } | |
135 | ||
73a40064 | 136 | void platform_send_ipi_cpu(unsigned int cpu, int irq) |
c51b4488 | 137 | { |
73a40064 | 138 | int offset = (irq == IRQ_SUPPLE_0) ? 6 : 8; |
c51b4488 GY |
139 | BUG_ON(cpu >= 2); |
140 | SSYNC(); | |
73a40064 | 141 | bfin_write_SICB_SYSCR(bfin_read_SICB_SYSCR() | (1 << (offset + cpu))); |
c51b4488 GY |
142 | SSYNC(); |
143 | } | |
144 | ||
73a40064 | 145 | void platform_clear_ipi(unsigned int cpu, int irq) |
c51b4488 | 146 | { |
73a40064 | 147 | int offset = (irq == IRQ_SUPPLE_0) ? 10 : 12; |
c51b4488 GY |
148 | BUG_ON(cpu >= 2); |
149 | SSYNC(); | |
73a40064 | 150 | bfin_write_SICB_SYSCR(bfin_read_SICB_SYSCR() | (1 << (offset + cpu))); |
c51b4488 GY |
151 | SSYNC(); |
152 | } | |
0d152c27 YL |
153 | |
154 | /* | |
155 | * Setup core B's local core timer. | |
156 | * In SMP, core timer is used for clock event device. | |
157 | */ | |
158 | void __cpuinit bfin_local_timer_setup(void) | |
159 | { | |
160 | #if defined(CONFIG_TICKSOURCE_CORETMR) | |
1907d8be TG |
161 | struct irq_data *data = irq_get_irq_data(IRQ_CORETMR); |
162 | struct irq_chip *chip = irq_data_get_irq_chip(data); | |
91796c23 | 163 | |
0d152c27 YL |
164 | bfin_coretmr_init(); |
165 | bfin_coretmr_clockevent_init(); | |
91796c23 | 166 | |
1907d8be | 167 | chip->irq_unmask(data); |
0d152c27 YL |
168 | #else |
169 | /* Power down the core timer, just to play safe. */ | |
170 | bfin_write_TCNTL(0); | |
171 | #endif | |
172 | ||
173 | } |