diff --git a/Kernel/Arch/aarch64/RPi/Timer.cpp b/Kernel/Arch/aarch64/RPi/Timer.cpp index 1b7ae0e5f01..1649ce9a39a 100644 --- a/Kernel/Arch/aarch64/RPi/Timer.cpp +++ b/Kernel/Arch/aarch64/RPi/Timer.cpp @@ -30,7 +30,8 @@ enum FlagBits { }; Timer::Timer() - : m_registers(MMIO::the().peripheral(0x3000)) + : IRQHandler(1) + , m_registers(MMIO::the().peripheral(0x3000)) { } @@ -51,6 +52,41 @@ u64 Timer::microseconds_since_boot() return (static_cast(high) << 32) | low; } +bool Timer::handle_irq(RegisterState const&) +{ + dbgln("Timer fired: {} us", m_current_timer_value); + + m_current_timer_value += m_interrupt_interval; + set_compare(TimerID::Timer1, m_current_timer_value); + + clear_interrupt(TimerID::Timer1); + return true; +}; + +void Timer::enable_interrupt_mode() +{ + m_current_timer_value = microseconds_since_boot(); + m_current_timer_value += m_interrupt_interval; + set_compare(TimerID::Timer1, m_current_timer_value); + + enable_irq(); +} + +void Timer::set_interrupt_interval_usec(u32 interrupt_interval) +{ + m_interrupt_interval = interrupt_interval; +} + +void Timer::clear_interrupt(TimerID id) +{ + m_registers->control_and_status = 1 << to_underlying(id); +} + +void Timer::set_compare(TimerID id, u32 compare) +{ + m_registers->compare[to_underlying(id)] = compare; +} + class SetClockRateMboxMessage : Mailbox::Message { public: u32 clock_id; diff --git a/Kernel/Arch/aarch64/RPi/Timer.h b/Kernel/Arch/aarch64/RPi/Timer.h index 59216760cff..f6bd611b9d0 100644 --- a/Kernel/Arch/aarch64/RPi/Timer.h +++ b/Kernel/Arch/aarch64/RPi/Timer.h @@ -7,18 +7,22 @@ #pragma once #include +#include namespace Kernel::RPi { struct TimerRegisters; -class Timer { +class Timer : public IRQHandler { public: Timer(); static Timer& the(); u64 microseconds_since_boot(); + void set_interrupt_interval_usec(u32); + void enable_interrupt_mode(); + enum class ClockID { Reserved = 0, EMMC = 1, @@ -39,7 +43,21 @@ public: static u32 set_clock_rate(ClockID, u32 rate_hz, bool skip_setting_turbo = true); private: + enum class TimerID : u32 { + Timer0 = 0, + Timer1 = 1, + Timer2 = 2, + Timer3 = 3, + }; + void set_compare(TimerID, u32 compare); + void clear_interrupt(TimerID); + + //^ IRQHandler + virtual bool handle_irq(RegisterState const&) override; + TimerRegisters volatile* m_registers; + u32 m_interrupt_interval { 0 }; + u32 m_current_timer_value { 0 }; }; }