FOC: Basic Arndale multi-core support
Second CPU is up and receives timer interrupts. Caches are still disabled.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
{}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
55
kernel/fiasco/src/kern/timer_tick-multi-vector.cpp
Normal file
55
kernel/fiasco/src/kern/timer_tick-multi-vector.cpp
Normal 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();
|
||||
}
|
||||
Reference in New Issue
Block a user