FOC: Basic Arndale multi-core support

Second CPU is up and receives timer interrupts. Caches are still disabled.
This commit is contained in:
Sebastian Sumpf
2013-02-13 16:09:27 +01:00
parent 64302baeb6
commit 3f42399fbb
15 changed files with 212 additions and 48 deletions

View File

@@ -85,7 +85,7 @@ config ABI_VF
config PF_ARM_MP_CAPABLE
bool
default y if ARM_MPCORE || ARM_CORTEX_A9
default y if ARM_MPCORE || ARM_CORTEX_A9 || ARM_CORTEX_A15
config CAN_ARM_CPU_SA1100
bool

View File

@@ -25,7 +25,7 @@ set_asid()
{}
//---------------------------------------------------------------------------
IMPLEMENTATION [arm && armv6plus && (mpcore || armca9)]:
IMPLEMENTATION [arm && armv6plus && (mpcore || armca9 || armca15)]:
enum
{
@@ -33,7 +33,7 @@ enum
};
//---------------------------------------------------------------------------
IMPLEMENTATION [arm && armv6plus && !(mpcore || armca9)]:
IMPLEMENTATION [arm && armv6plus && !(mpcore || armca9 || armca15)]:
enum
{

View File

@@ -6,17 +6,20 @@ PREPROCESS_PARTS += exynos5 libuart
PREPROCESS_PARTS += $(if $(CONFIG_PF_EXYNOS5_ARNDALE), exynos5_arndale pic_gic)
CONFIG_KERNEL_LOAD_ADDR := 0x40000000
#no memory mapped SCU on exynos5
MPCORE_PHYS_BASE := 0x0
INTERFACES_KERNEL+= $(if $(CONFIG_PF_EXYNOS5_ARNDALE),gic)
bootstrap_IMPL += bootstrap-arm-exynos5
clock_IMPL += clock-generic
config_IMPL += config-arm-exynos5
kernel_uart_IMPL += kernel_uart-arm-exynos5
mem_layout_IMPL += mem_layout-arm-exynos5
pic_IMPL += pic-gic pic-arm-gic-exynos5
reset_IMPL += reset-arm-exynos5
timer_IMPL += timer-arm-exynos5
timer_tick_IMPL += timer_tick-single-vector
uart_IMPL += uart-arm-exynos5
warn_IMPL += warn warn-exynos5
bootstrap_IMPL += bootstrap-arm-exynos5
clock_IMPL += clock-generic
config_IMPL += config-arm-exynos5
kernel_uart_IMPL += kernel_uart-arm-exynos5
mem_layout_IMPL += mem_layout-arm-exynos5
pic_IMPL += pic-gic pic-arm-gic-exynos5
platform_control_IMPL += platform_control-arm-exynos5
reset_IMPL += reset-arm-exynos5
timer_IMPL += timer-arm-exynos5
timer_tick_IMPL += timer_tick-multi-vector
uart_IMPL += uart-arm-exynos5
warn_IMPL += warn warn-exynos5

View File

@@ -16,4 +16,5 @@ map_hw(void *pd)
map_dev<Mem_layout::Devices2_phys_base>(pd, 2);
map_dev<Mem_layout::Devices3_phys_base>(pd, 3);
map_dev<Mem_layout::Devices4_phys_base>(pd, 4);
map_dev<Mem_layout::Devices5_phys_base>(pd, 5);
}

View File

@@ -8,6 +8,7 @@ public:
Devices2_phys_base = 0x12c00000,
Devices3_phys_base = 0x10400000,
Devices4_phys_base = 0x12d00000,
Devices5_phys_base = 0x02000000,
};
enum Virt_layout_exynos5 : Address {

View File

@@ -29,3 +29,11 @@ IMPLEMENT inline
void Pic::restore_all(Status)
{}
// ------------------------------------------------------------------------
IMPLEMENTATION [arm && mp && pic_gic && exynos5]:
PUBLIC static
void Pic::init_ap(unsigned)
{
gic->init_ap();
}

View File

@@ -0,0 +1,22 @@
INTERFACE [arm && mp && exynos5]:
#include "types.h"
IMPLEMENTATION [arm && mp && exynos5]:
#include "io.h"
#include "kmem.h"
#include "stdio.h"
PUBLIC static
void
Platform_control::boot_ap_cpus(Address phys_tramp_mp_addr)
{
// Write start address to iRam base (0x2020000). This is checked by the app
// cpus wihtin an wfe (wait-for event) loop.
printf("START CPUs\n");
Io::write<Mword>(phys_tramp_mp_addr, Kmem::Devices5_map_base + 0x20000);
// wake-up cpus
asm volatile("dsb; sev" : : : "memory");
}

View File

@@ -1,12 +1,13 @@
INTERFACE [arm & exynos5]:
#include "kmem.h"
#include "processor.h"
EXTENSION class Timer
{
public:
enum {
BASE = Kmem::Timer_map_base,
BASE = Kmem::Timer_map_base,
CFG0 = BASE,
CFG1 = BASE + 0x4,
TCON = BASE + 0x8,
@@ -16,13 +17,15 @@ public:
ONE_MS = 33000, /* HZ */
};
static unsigned irq() { return 68; /* timer0 */ }
static unsigned irq() { return 68 + Proc::cpu_id(); }
};
IMPLEMENTATION [arm && exynos5]:
#include "mmu.h"
#include "cpu.h"
#include "io.h"
#include "irq_mgr.h"
#include "mmu.h"
IMPLEMENT inline
void
@@ -31,25 +34,40 @@ Timer::update_one_shot(Unsigned64 wakeup)
(void)wakeup;
}
static inline
Mword
tcon_to_timer(Mword val, unsigned cpu_id)
{
return cpu_id == 0 ? val : (val << (4 + (4 * cpu_id)));
}
IMPLEMENT
void Timer::init(unsigned)
{
/* prescaler to one */
Io::write<Mword>(0x1, CFG0);
/* divider to 1 */
Io::write<Mword>(0x0, CFG1);
unsigned cpu_id = Proc::cpu_id();
/* program 1ms */
Io::write<Mword>(ONE_MS, TCNTB0);
Io::write<Mword>(0x0, TCMPB0);
if (!Cpu::boot_cpu()->phys_id() == cpu_id)
{
// prescaler to one
Io::write<Mword>(0x1, CFG0);
// divider to 1
Io::write<Mword>(0x0, CFG1);
}
// program 1ms
Mword offset = 0xc * cpu_id;
Io::write<Mword>(ONE_MS, TCNTB0 + offset);
Io::write<Mword>(0x0, TCMPB0 + offset);
/* enable IRQ */
Io::write<Mword>(0x1, TINT_STAT);
// enable IRQ
Io::set<Mword>(0x1 << cpu_id, TINT_STAT);
/* load and start timer in invterval mode*/
Io::write<Mword>(0xa, TCON);
Io::write<Mword>(0x9, TCON);
// load and start timer in invterval mode
Mword tcon = Io::read<Mword>(TCON);
Io::write<Mword>(tcon | tcon_to_timer(0xa, cpu_id), TCON);
Io::write<Mword>(tcon | tcon_to_timer(0x9, cpu_id), TCON);
// route IRQ to this CPU
Irq_mgr::mgr->set_cpu(irq(), cpu_id);
}
IMPLEMENT inline NEEDS["config.h", "kip.h"]
@@ -65,5 +83,6 @@ Timer::system_clock()
PUBLIC static inline NEEDS["io.h"]
void Timer::acknowledge()
{
Io::set<Mword>(0x20, TINT_STAT);
Mword stat = Io::read<Mword>(TINT_STAT);
Io::write<Mword>(stat & (0x1f | (0x20 << Proc::cpu_id())), TINT_STAT);
}

View File

@@ -309,7 +309,44 @@ Cpu::early_init_platform()
}
//---------------------------------------------------------------------------
IMPLEMENTATION [arm && !(mpcore || armca9)]:
IMPLEMENTATION [arm && armca15]:
PRIVATE static inline void
Cpu::early_init_platform()
{
Io::write<Mword>(Io::read<Mword>(Mem_layout::Gic_cpu_map_base + 0) | 1,
Mem_layout::Gic_cpu_map_base + 0);
Io::write<Mword>(Io::read<Mword>(Mem_layout::Gic_dist_map_base + 0) | 1,
Mem_layout::Gic_dist_map_base + 0);
Mem_unit::clean_dcache();
enable_smp();
}
//---------------------------------------------------------------------------
IMPLEMENTATION [arm && mp && (mpcore || armca9)]:
PUBLIC static inline NEEDS["mem_layout.h", "io.h"]
int
Cpu::num_cpus()
{
return (Io::read<Mword>(Mem_layout::Mp_scu_map_base + 4) & 3) + 1;
}
//---------------------------------------------------------------------------
IMPLEMENTATION [arm && mp && armca15]:
PUBLIC static inline int
Cpu::num_cpus()
{
unsigned num;
asm volatile ("mrc p15, 1, %0, c9, c0, 2" : "=r"(num));
return ((num >> 24) & 0x3)+ 1;
}
//---------------------------------------------------------------------------
IMPLEMENTATION [arm && !(mpcore || armca9 || armca15)]:
PRIVATE static inline void Cpu::early_init_platform()
{}

View File

@@ -45,9 +45,9 @@ Kernel_thread::boot_app_cpus()
extern volatile Mword _tramp_mp_startup_pdbr;
extern volatile Mword _tramp_mp_start_dcr;
unsigned num_ap_cpus = (Io::read<Mword>(Mem_layout::Mp_scu_map_base + 4) & 3);
unsigned num_ap_cpus = Cpu::num_cpus();
printf("Number of CPUs: %d\n", num_ap_cpus + 1);
printf("Number of CPUs: %d\n", num_ap_cpus);
_tramp_mp_startup_cp15_c1 = Config::Cache_enabled
? Cpu::Cp15_c1_cache_enabled : Cpu::Cp15_c1_cache_disabled;

View File

@@ -42,7 +42,7 @@ public:
};
//---------------------------------------------------------------------------
INTERFACE[arm && !(mpcore || armca9)]:
INTERFACE[arm && !(mpcore || armca9 || armca15)]:
EXTENSION class Mem_page_attr
{
@@ -59,7 +59,7 @@ public:
};
//---------------------------------------------------------------------------
INTERFACE[arm && (mpcore || armca9)]:
INTERFACE[arm && (mpcore || armca9 || armca15)]:
EXTENSION class Mem_page_attr
{
@@ -78,7 +78,7 @@ public:
};
//---------------------------------------------------------------------------
INTERFACE[arm && armca9]:
INTERFACE[arm && (armca9 || armca15)]:
EXTENSION class Page_table
{

View File

@@ -11,7 +11,7 @@ public:
};
// ------------------------------------------------------------------------
INTERFACE [arm && perf_cnt && !(mpcore || armca8 || armca9)]:
INTERFACE [arm && perf_cnt && !(mpcore || armca8 || armca9 || armca15)]:
EXTENSION class Perf_cnt
{
@@ -81,7 +81,7 @@ private:
};
// ------------------------------------------------------------------------
INTERFACE [arm && perf_cnt && (armca8 || armca9)]:
INTERFACE [arm && perf_cnt && (armca8 || armca9 || armca15)]:
EXTENSION class Perf_cnt
{
@@ -184,7 +184,7 @@ private:
};
// ------------------------------------------------------------------------
INTERFACE [arm && perf_cnt && armca9]:
INTERFACE [arm && perf_cnt && (armca9 || armca15)]:
EXTENSION class Perf_cnt
{
@@ -199,7 +199,7 @@ private:
IMPLEMENTATION [arm && perf_cnt]:
// ------------------------------------------------------------------------
IMPLEMENTATION [arm && perf_cnt && !(mpcore || armca8 || armca9)]:
IMPLEMENTATION [arm && perf_cnt && !(mpcore || armca8 || armca9 || armca15)]:
char const *Perf_cnt::perf_type_str = "none";
@@ -284,7 +284,7 @@ Perf_cnt::mon_event_type(int nr)
{ return Io::read<unsigned char>(mon_event_type_addr(nr)); }
// ------------------------------------------------------------------------
IMPLEMENTATION [arm && perf_cnt && (armca8 || armca9)]:
IMPLEMENTATION [arm && perf_cnt && (armca8 || armca9 || armca15)]:
#include "cpu.h"

View File

@@ -44,11 +44,13 @@ _tramp_mp_entry:
msr cpsr_c, r0
// enable SMP
#ifndef CONFIG_ARM_CORTEX_A15
adr r0, .Lmpcore_phys_base
ldr r0, [r0]
ldr r1, [r0]
orr r1, #1
str r1, [r0]
#endif
#ifdef CONFIG_ARM_V7
bl invalidate_l1_v7
@@ -65,7 +67,7 @@ _tramp_mp_entry:
#ifdef CONFIG_ARM_V7
// ACTRL is implementation defined
mrc p15, 0, r0, c0, c0, 0 // read MIDR
adr r3, .Lactrl_cpuid_a9 // load addr
adr r3, .Lactrl_cpuid // load addr
ldm r3, {r1,r2} // load mask + val
and r0, r1 // apply mask
teq r0, r2 // check value
@@ -73,9 +75,11 @@ _tramp_mp_entry:
#endif
mrc p15, 0, r0, c1, c0, 1
#ifdef CONFIG_ARM_V7
tst r0, #0x40
bne 2f
#ifdef CONFIG_ARM_CORTEX_A15
orr r0, r0, #0x40
#elif defined CONFIG_ARM_V7
tst r0, #0x40
bne 2f
orr r0, r0, #0x41
#else
orr r0, r0, #0x20
@@ -114,10 +118,20 @@ _tramp_mp_entry:
.Lmpcore_phys_base:
.long MPCORE_PHYS_BASE
// only one currently
.Lactrl_cpuid_a9:
#ifdef CONFIG_ARM_CORTEX_A9
.Lactrl_cpuid:
.long 0xff0ffff0
.long 0x410fc090
#elif defined CONFIG_ARM_CORTEX_A15
.Lactrl_cpuid:
.long 0xff0ffff0
.long 0x410fc0f0
#else
.Lactrl_cpuid:
.long 0xffffffff
.long 0x0
#endif
// we run paged now
_tramp_mp_virt:

View File

@@ -124,5 +124,9 @@ IMPLEMENT
void
Irq_mgr::set_cpu(Mword irqnum, unsigned cpu) const
{
WARNX(Warning, "IRQ%ld: ignoring CPU setting (%d).\n", irqnum, cpu);
Irq i = chip(irqnum);
if (!i.chip)
return;
i.chip->set_cpu(i.pin, cpu);
}

View File

@@ -0,0 +1,55 @@
INTERFACE:
#include "types.h"
#include "per_cpu_data.h"
EXTENSION class Timer_tick
{
public:
static Per_cpu<Timer_tick> _glbl_timer;
Timer_tick()
{
if (Proc::cpu_id())
set_hit(&handler_app);
else
set_hit(&handler_sys_time);
}
};
IMPLEMENTATION:
#include "timer.h"
DEFINE_PER_CPU Per_cpu<Timer_tick> Timer_tick::_glbl_timer;
IMPLEMENT void
Timer_tick::setup(unsigned cpu)
{
if (!allocate_irq(&_glbl_timer.cpu(cpu), Timer::irq()))
panic("Could not allocate scheduling IRQ %d\n", Timer::irq());
_glbl_timer.cpu(cpu).set_mode(Timer::irq_mode());
}
IMPLEMENT
void
Timer_tick::enable(unsigned)
{
_glbl_timer.current().chip()->unmask(_glbl_timer.current().pin());
}
IMPLEMENT
void
Timer_tick::disable(unsigned)
{
_glbl_timer.current().chip()->mask(_glbl_timer.current().pin());
}
PUBLIC inline NEEDS["timer.h"]
void
Timer_tick::ack()
{
Timer::acknowledge();
Irq_base::ack();
}