blob: cf38379480b5dbb95f329e3242feb2d11cc68a84 [file]
/*
* Copyright (c) 2020, 2021 Antony Pavlov <antonynpavlov@gmail.com>
* Copyright (c) 2021 Remy Luisant <remy@luisant.ca>
*
* Based on riscv_machine_timer.c and xtensa_sys_timer.c
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/init.h>
#include <zephyr/drivers/timer/system_timer.h>
#include <zephyr/irq.h>
#include <zephyr/sys/clock.h>
#include <soc.h>
#include <mips/mipsregs.h>
static ALWAYS_INLINE void set_cp0_compare(uint32_t time)
{
_mips_write_32bit_c0_register(CP0_COMPARE, time);
}
static ALWAYS_INLINE uint32_t get_cp0_count(void)
{
return _mips_read_32bit_c0_register(CP0_COUNT);
}
/*
* A free-running 32-bit CP0 Count with an equality-match Compare register.
* TIMER_CORE_COUNTER_WIDTH defaults to the native width, so the core masks
* deltas at the 2^32 wrap. Compare fires only on Count == Compare, so a target
* already behind is missed until Count comes all the way round: that is the
* COMPARE_EXACT backend, and the core writes the register through its verify
* loop. Writing Compare also clears the pending interrupt.
*/
#define TIMER_CORE_BACKEND_COMPARE_EXACT
static inline uint32_t timer_driver_cycle_get(void)
{
return get_cp0_count();
}
static inline void timer_driver_set_compare(uint64_t cycles)
{
set_cp0_compare((uint32_t)cycles);
}
#include "system_timer_generic.h"
static void timer_isr(const void *arg)
{
ARG_UNUSED(arg);
timer_core_announce();
}
static int sys_clock_driver_init(void)
{
IRQ_CONNECT(MIPS_MACHINE_TIMER_IRQ, 0, timer_isr, NULL, 0);
timer_core_init();
irq_enable(MIPS_MACHINE_TIMER_IRQ);
return 0;
}
SYS_INIT(sys_clock_driver_init, PRE_KERNEL_2,
CONFIG_SYSTEM_CLOCK_INIT_PRIORITY);