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 config PF_ARM_MP_CAPABLE
bool 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 config CAN_ARM_CPU_SA1100
bool bool

View File

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

View File

@@ -6,17 +6,20 @@ PREPROCESS_PARTS += exynos5 libuart
PREPROCESS_PARTS += $(if $(CONFIG_PF_EXYNOS5_ARNDALE), exynos5_arndale pic_gic) PREPROCESS_PARTS += $(if $(CONFIG_PF_EXYNOS5_ARNDALE), exynos5_arndale pic_gic)
CONFIG_KERNEL_LOAD_ADDR := 0x40000000 CONFIG_KERNEL_LOAD_ADDR := 0x40000000
#no memory mapped SCU on exynos5
MPCORE_PHYS_BASE := 0x0
INTERFACES_KERNEL+= $(if $(CONFIG_PF_EXYNOS5_ARNDALE),gic) INTERFACES_KERNEL+= $(if $(CONFIG_PF_EXYNOS5_ARNDALE),gic)
bootstrap_IMPL += bootstrap-arm-exynos5 bootstrap_IMPL += bootstrap-arm-exynos5
clock_IMPL += clock-generic clock_IMPL += clock-generic
config_IMPL += config-arm-exynos5 config_IMPL += config-arm-exynos5
kernel_uart_IMPL += kernel_uart-arm-exynos5 kernel_uart_IMPL += kernel_uart-arm-exynos5
mem_layout_IMPL += mem_layout-arm-exynos5 mem_layout_IMPL += mem_layout-arm-exynos5
pic_IMPL += pic-gic pic-arm-gic-exynos5 pic_IMPL += pic-gic pic-arm-gic-exynos5
reset_IMPL += reset-arm-exynos5 platform_control_IMPL += platform_control-arm-exynos5
timer_IMPL += timer-arm-exynos5 reset_IMPL += reset-arm-exynos5
timer_tick_IMPL += timer_tick-single-vector timer_IMPL += timer-arm-exynos5
uart_IMPL += uart-arm-exynos5 timer_tick_IMPL += timer_tick-multi-vector
warn_IMPL += warn warn-exynos5 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::Devices2_phys_base>(pd, 2);
map_dev<Mem_layout::Devices3_phys_base>(pd, 3); map_dev<Mem_layout::Devices3_phys_base>(pd, 3);
map_dev<Mem_layout::Devices4_phys_base>(pd, 4); 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, Devices2_phys_base = 0x12c00000,
Devices3_phys_base = 0x10400000, Devices3_phys_base = 0x10400000,
Devices4_phys_base = 0x12d00000, Devices4_phys_base = 0x12d00000,
Devices5_phys_base = 0x02000000,
}; };
enum Virt_layout_exynos5 : Address { enum Virt_layout_exynos5 : Address {

View File

@@ -29,3 +29,11 @@ IMPLEMENT inline
void Pic::restore_all(Status) 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]: INTERFACE [arm & exynos5]:
#include "kmem.h" #include "kmem.h"
#include "processor.h"
EXTENSION class Timer EXTENSION class Timer
{ {
public: public:
enum { enum {
BASE = Kmem::Timer_map_base, BASE = Kmem::Timer_map_base,
CFG0 = BASE, CFG0 = BASE,
CFG1 = BASE + 0x4, CFG1 = BASE + 0x4,
TCON = BASE + 0x8, TCON = BASE + 0x8,
@@ -16,13 +17,15 @@ public:
ONE_MS = 33000, /* HZ */ ONE_MS = 33000, /* HZ */
}; };
static unsigned irq() { return 68; /* timer0 */ } static unsigned irq() { return 68 + Proc::cpu_id(); }
}; };
IMPLEMENTATION [arm && exynos5]: IMPLEMENTATION [arm && exynos5]:
#include "mmu.h" #include "cpu.h"
#include "io.h" #include "io.h"
#include "irq_mgr.h"
#include "mmu.h"
IMPLEMENT inline IMPLEMENT inline
void void
@@ -31,25 +34,40 @@ Timer::update_one_shot(Unsigned64 wakeup)
(void)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 IMPLEMENT
void Timer::init(unsigned) void Timer::init(unsigned)
{ {
/* prescaler to one */ unsigned cpu_id = Proc::cpu_id();
Io::write<Mword>(0x1, CFG0);
/* divider to 1 */
Io::write<Mword>(0x0, CFG1);
/* program 1ms */ if (!Cpu::boot_cpu()->phys_id() == cpu_id)
Io::write<Mword>(ONE_MS, TCNTB0); {
Io::write<Mword>(0x0, TCMPB0); // 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 */ // enable IRQ
Io::write<Mword>(0x1, TINT_STAT); Io::set<Mword>(0x1 << cpu_id, TINT_STAT);
/* load and start timer in invterval mode*/ // load and start timer in invterval mode
Io::write<Mword>(0xa, TCON); Mword tcon = Io::read<Mword>(TCON);
Io::write<Mword>(0x9, 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"] IMPLEMENT inline NEEDS["config.h", "kip.h"]
@@ -65,5 +83,6 @@ Timer::system_clock()
PUBLIC static inline NEEDS["io.h"] PUBLIC static inline NEEDS["io.h"]
void Timer::acknowledge() 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() 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_startup_pdbr;
extern volatile Mword _tramp_mp_start_dcr; 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 _tramp_mp_startup_cp15_c1 = Config::Cache_enabled
? Cpu::Cp15_c1_cache_enabled : Cpu::Cp15_c1_cache_disabled; ? 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 EXTENSION class Mem_page_attr
{ {
@@ -59,7 +59,7 @@ public:
}; };
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
INTERFACE[arm && (mpcore || armca9)]: INTERFACE[arm && (mpcore || armca9 || armca15)]:
EXTENSION class Mem_page_attr EXTENSION class Mem_page_attr
{ {
@@ -78,7 +78,7 @@ public:
}; };
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
INTERFACE[arm && armca9]: INTERFACE[arm && (armca9 || armca15)]:
EXTENSION class Page_table 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 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 EXTENSION class Perf_cnt
{ {
@@ -184,7 +184,7 @@ private:
}; };
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
INTERFACE [arm && perf_cnt && armca9]: INTERFACE [arm && perf_cnt && (armca9 || armca15)]:
EXTENSION class Perf_cnt EXTENSION class Perf_cnt
{ {
@@ -199,7 +199,7 @@ private:
IMPLEMENTATION [arm && perf_cnt]: 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"; 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)); } { 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" #include "cpu.h"

View File

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

View File

@@ -124,5 +124,9 @@ IMPLEMENT
void void
Irq_mgr::set_cpu(Mword irqnum, unsigned cpu) const 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();
}