From 7cbfcd26a26533e5a7fe9f659e03ba459de74d42 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Boric Date: Fri, 3 Jun 2016 11:21:28 +0200 Subject: [PATCH] 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). --- minix/kernel/arch/earm/arch_clock.c | 2 +- minix/kernel/arch/earm/bsp/rpi/rpi_intr.c | 8 +- minix/kernel/arch/earm/bsp/rpi/rpi_timer.c | 77 ++++++++++++++++--- .../arch/earm/bsp/rpi/rpi_timer_registers.h | 19 +++++ 4 files changed, 91 insertions(+), 15 deletions(-) diff --git a/minix/kernel/arch/earm/arch_clock.c b/minix/kernel/arch/earm/arch_clock.c index f26370c37..431556fbe 100644 --- a/minix/kernel/arch/earm/arch_clock.c +++ b/minix/kernel/arch/earm/arch_clock.c @@ -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); diff --git a/minix/kernel/arch/earm/bsp/rpi/rpi_intr.c b/minix/kernel/arch/earm/bsp/rpi/rpi_intr.c index 53e85c09a..483d3d46d 100644 --- a/minix/kernel/arch/earm/bsp/rpi/rpi_intr.c +++ b/minix/kernel/arch/earm/bsp/rpi/rpi_intr.c @@ -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; } diff --git a/minix/kernel/arch/earm/bsp/rpi/rpi_timer.c b/minix/kernel/arch/earm/bsp/rpi/rpi_timer.c index 1b400450a..4f83252fb 100644 --- a/minix/kernel/arch/earm/bsp/rpi/rpi_timer.c +++ b/minix/kernel/arch/earm/bsp/rpi/rpi_timer.c @@ -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); + } } diff --git a/minix/kernel/arch/earm/bsp/rpi/rpi_timer_registers.h b/minix/kernel/arch/earm/bsp/rpi/rpi_timer_registers.h index 351f99901..4dd3a686f 100644 --- a/minix/kernel/arch/earm/bsp/rpi/rpi_timer_registers.h +++ b/minix/kernel/arch/earm/bsp/rpi/rpi_timer_registers.h @@ -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 */