kernel: add support for system timer

This timer is the one we're supposed to use all along, but QEMU doesn't
support it for now, so we keep the ARM internal timers around if needed.
These timers shouldn't be used since they aren't memory-mapped and thus
unsuitable for MINIX 3 (for the user-mapped page).
This commit is contained in:
Jean-Baptiste Boric
2016-06-03 11:21:28 +02:00
parent b76b176eaf
commit 7cbfcd26a2
4 changed files with 91 additions and 15 deletions

View File

@@ -40,7 +40,7 @@ int init_local_timer(unsigned freq)
tsc_per_ms[0] = 15000;
} else if (BOARD_IS_RPI_2_B(machine.board_id) ||
BOARD_IS_RPI_3_B(machine.board_id)) {
tsc_per_ms[0] = read_cntfrq() / 1000;
tsc_per_ms[0] = 1000;
}
else {
panic("Can not do the clock setup. machine (0x%08x) is unknown\n",machine.board_id);

View File

@@ -25,6 +25,7 @@ static kern_phys_map intr_phys_map;
static kern_phys_map timer_phys_map;
static irq_hook_t dummy8_irq_hook;
static irq_hook_t dummy40_irq_hook;
static irq_hook_t dummy41_irq_hook;
static irq_hook_t dummy51_irq_hook;
@@ -71,9 +72,10 @@ intr_init(const int auto_eoi)
mmio_write(rpi2_intr.core_base + QA7_CORE0TIMER, 0x8);
/* Register dummy irq handlers */
put_irq_handler(&dummy8_irq_hook, 8, (irq_handler_t)dummy_irq_handler);
put_irq_handler(&dummy41_irq_hook, 41, (irq_handler_t)dummy_irq_handler);
put_irq_handler(&dummy51_irq_hook, 51, (irq_handler_t)dummy_irq_handler);
put_irq_handler(&dummy8_irq_hook, 8, dummy_irq_handler);
put_irq_handler(&dummy40_irq_hook, 40, dummy_irq_handler);
put_irq_handler(&dummy41_irq_hook, 41, dummy_irq_handler);
put_irq_handler(&dummy51_irq_hook, 51, dummy_irq_handler);
return 0;
}

View File

@@ -20,16 +20,18 @@ static irq_hook_t arm_timer_hook;
struct arm_timer
{
vir_bytes st_base;
int size;
int irq_nr;
u32_t freq;
int st_workaround;
};
static struct arm_timer arm_timer = {
.irq_nr = RPI2_IRQ_ARMTIMER,
.freq = 0,
};
static struct arm_timer arm_timer;
static kern_phys_map stc_timer_phys_map;
static kern_phys_map st_timer_phys_map;
static kern_phys_map st_timer_user_phys_map;
int
bsp_register_timer_handler(const irq_handler_t handler)
@@ -51,8 +53,11 @@ bsp_register_timer_handler(const irq_handler_t handler)
/* callback for when the free running clock gets mapped */
int
kern_phys_fr_user_mapped(vir_bytes id, phys_bytes address)
kern_phys_st_user_mapped(vir_bytes id, phys_bytes address)
{
arm_frclock.tcrr = address + RPI_ST_CLO;
arm_frclock.hz = RPI_ST_FREQ;
return 0;
}
@@ -60,6 +65,41 @@ void
bsp_timer_init(unsigned freq)
{
arm_timer.freq = freq;
if (BOARD_IS_RPI_2_B(machine.board_id) ||
BOARD_IS_RPI_3_B(machine.board_id)) {
arm_timer.st_base = RPI_ST_BASE;
arm_timer.size = 0x1000; /* 4K */
} else {
panic
("Can not do the timer setup. machine (0x%08x) is unknown\n",
machine.board_id);
}
kern_phys_map_ptr(arm_timer.st_base, arm_timer.size,
VMMF_UNCACHED | VMMF_WRITE,
&st_timer_phys_map, (vir_bytes) & arm_timer.st_base);
/* Check if we need to workaround QEMU's lack of ST support */
if (mmio_read(arm_timer.st_base + RPI_ST_CLO) == 0) {
/*
* Uh oh. We'll have to rely on the ARM processor's internal
* timers. Not good.
*/
printf("Working around lack of system timer support - please fix\n");
arm_timer.st_workaround = 1;
arm_timer.irq_nr = RPI2_IRQ_ARMTIMER;
}
else {
arm_timer.st_workaround = 0;
arm_timer.irq_nr = RPI_IRQ_ST_C3;
/* the timer is also mapped in user space hence the this */
/* second mapping and callback to set kerninfo frclock_tcrr */
kern_req_phys_map(arm_timer.st_base, ARM_PAGE_SIZE,
VMMF_UNCACHED | VMMF_USER,
&st_timer_user_phys_map, kern_phys_st_user_mapped, 0);
}
}
void
@@ -71,15 +111,30 @@ bsp_timer_stop()
void
bsp_timer_int_handler()
{
/* Arm next timer countdown and enable timer */
write_cntv_cval(-1);
write_cntv_tval(read_cntfrq() / arm_timer.freq);
write_cntv_ctl(ARMTIMER_ENABLE);
if (arm_timer.st_workaround) {
/* Arm next timer countdown and enable timer */
write_cntv_cval(-1);
write_cntv_tval(read_cntfrq() / arm_timer.freq);
write_cntv_ctl(ARMTIMER_ENABLE);
}
else {
/* Set next timer alarm and enable timer */
u32_t next_alarm = mmio_read(arm_timer.st_base + RPI_ST_CLO);
next_alarm += RPI_ST_FREQ / arm_timer.freq;
mmio_write(arm_timer.st_base + RPI_ST_C3, next_alarm);
mmio_write(arm_timer.st_base + RPI_ST_CS, RPI_ST_M3);
}
}
/* Use the free running clock as TSC */
void
read_tsc_64(u64_t * t)
{
*t = read_cntv_cval();
if (arm_timer.st_workaround)
*t = read_cntv_cval();
else {
*t = mmio_read(arm_timer.st_base + RPI_ST_CHI);
*t = (*t << 32) | mmio_read(arm_timer.st_base + RPI_ST_CLO);
}
}

View File

@@ -8,4 +8,23 @@
#define RPI2_IRQ_ARMTIMER 3
#define RPI_ST_BASE 0x3f003000
#define RPI_ST_CS 0x0
#define RPI_ST_CLO 0x4
#define RPI_ST_CHI 0x8
#define RPI_ST_C0 0xc
#define RPI_ST_C1 0x10
#define RPI_ST_C2 0x14
#define RPI_ST_C3 0x18
#define RPI_ST_M0 0x1
#define RPI_ST_M1 0x2
#define RPI_ST_M2 0x4
#define RPI_ST_M3 0x8
#define RPI_IRQ_ST_C3 67
#define RPI_ST_FREQ 1000000
#endif /* _RPI_TIMER_REGISTERS_H */