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