Skip to content

Commit

Permalink
Kernel/aarch64: Make RPi::Timer a DeviceTree::Driver
Browse files Browse the repository at this point in the history
This driver doesn't actually get any info (like the physical address)
from the devicetree node for now.
  • Loading branch information
spholz authored and nico committed Nov 2, 2024
1 parent ed62026 commit d6a3500
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 12 deletions.
29 changes: 24 additions & 5 deletions Kernel/Arch/aarch64/RPi/Timer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
#include <Kernel/Arch/aarch64/RPi/MMIO.h>
#include <Kernel/Arch/aarch64/RPi/Mailbox.h>
#include <Kernel/Arch/aarch64/RPi/Timer.h>
#include <Kernel/Firmware/DeviceTree/DeviceTree.h>
#include <Kernel/Firmware/DeviceTree/Driver.h>
#include <Kernel/Firmware/DeviceTree/Management.h>

namespace Kernel::RPi {

Expand Down Expand Up @@ -43,11 +46,6 @@ Timer::Timer()

Timer::~Timer() = default;

NonnullLockRefPtr<Timer> Timer::initialize()
{
return adopt_lock_ref(*new Timer);
}

u64 Timer::microseconds_since_boot()
{
u32 high = m_registers->counter_high;
Expand Down Expand Up @@ -182,4 +180,25 @@ u32 Timer::get_clock_rate(ClockID clock_id)
return message_queue.get_clock_rate.rate_hz;
}

static constinit Array const compatibles_array = {
"brcm,bcm2835-system-timer"sv,
};

DEVICETREE_DRIVER(BCM2835TimerDriver, compatibles_array);

ErrorOr<void> BCM2835TimerDriver::probe(DeviceTree::Device const& device, StringView) const
{
DeviceTree::DeviceRecipe<NonnullLockRefPtr<HardwareTimerBase>> recipe {
name(),
device.node_name(),
[]() {
return adopt_nonnull_lock_ref_or_enomem(new (nothrow) Timer());
},
};

TimeManagement::add_recipe(move(recipe));

return {};
}

}
5 changes: 1 addition & 4 deletions Kernel/Arch/aarch64/RPi/Timer.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,9 @@ struct TimerRegisters;

class Timer final : public HardwareTimer<IRQHandler> {
public:
Timer();
virtual ~Timer();

static NonnullLockRefPtr<Timer> initialize();

virtual HardwareTimerType timer_type() const override { return HardwareTimerType::RPiTimer; }
virtual StringView model() const override { return "RPi Timer"sv; }

Expand Down Expand Up @@ -65,8 +64,6 @@ class Timer final : public HardwareTimer<IRQHandler> {
static u32 get_clock_rate(ClockID);

private:
Timer();

enum class TimerID : u32 {
Timer0 = 0,
Timer1 = 1,
Expand Down
38 changes: 35 additions & 3 deletions Kernel/Time/TimeManagement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*/

#include <AK/NeverDestroyed.h>
#include <AK/Singleton.h>
#include <AK/StdLibExtras.h>
#include <AK/Time.h>
Expand All @@ -28,6 +29,7 @@
#include <Kernel/Boot/CommandLine.h>
#include <Kernel/Firmware/ACPI/Parser.h>
#include <Kernel/Interrupts/InterruptDisabler.h>
#include <Kernel/Library/Panic.h>
#include <Kernel/Sections.h>
#include <Kernel/Tasks/PerformanceManager.h>
#include <Kernel/Tasks/Scheduler.h>
Expand All @@ -37,6 +39,7 @@

namespace Kernel {

static NeverDestroyed<Vector<DeviceTree::DeviceRecipe<NonnullLockRefPtr<HardwareTimerBase>>>> s_recipes;
static Singleton<TimeManagement> s_the;

bool TimeManagement::is_initialized()
Expand All @@ -49,6 +52,15 @@ TimeManagement& TimeManagement::the()
return *s_the;
}

void TimeManagement::add_recipe(DeviceTree::DeviceRecipe<NonnullLockRefPtr<HardwareTimerBase>> recipe)
{
// This function has to be called before TimeManagement is initialized,
// as we do not support dynamic registration of timers.
VERIFY(!is_initialized());

s_recipes->append(move(recipe));
}

// The s_scheduler_specific_current_time function provides a current time for scheduling purposes,
// which may not necessarily relate to wall time
static u64 (*s_scheduler_current_time)();
Expand Down Expand Up @@ -459,14 +471,34 @@ void TimeManagement::increment_time_since_boot_hpet()
#elif ARCH(AARCH64)
UNMAP_AFTER_INIT bool TimeManagement::probe_and_set_aarch64_hardware_timers()
{
m_hardware_timers.append(RPi::Timer::initialize());
m_system_timer = m_hardware_timers[0];
for (auto& recipe : *s_recipes) {
auto device_or_error = recipe.create_device();
if (device_or_error.is_error()) {
dmesgln("TimeManagement: Failed to create timer for device \"{}\" with driver {}: {}", recipe.node_name, recipe.driver_name, device_or_error.release_error());
continue;
}

m_hardware_timers.append(device_or_error.release_value());
}

if (m_hardware_timers.is_empty())
PANIC("TimeManagement: No supported timer found in devicetree");

// TODO: Use some kind of heuristic to decide which timer to use.
m_system_timer = m_hardware_timers.last();
dbgln("TimeManagement: System timer: {}", m_system_timer->model());

m_time_ticks_per_second = m_system_timer->ticks_per_second();

m_system_timer->set_callback([this]() {
auto seconds_since_boot = m_seconds_since_boot;
auto ticks_this_second = m_ticks_this_second;
auto delta_ns = static_cast<RPi::Timer*>(m_system_timer.ptr())->update_time(seconds_since_boot, ticks_this_second, false);

u64 delta_ns;
if (m_system_timer->timer_type() == HardwareTimerType::RPiTimer)
delta_ns = static_cast<RPi::Timer*>(m_system_timer.ptr())->update_time(seconds_since_boot, ticks_this_second, false);
else
VERIFY_NOT_REACHED();

u32 update_iteration = m_update2.fetch_add(1, AK::MemoryOrder::memory_order_acquire);
m_seconds_since_boot = seconds_since_boot;
Expand Down
3 changes: 3 additions & 0 deletions Kernel/Time/TimeManagement.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include <AK/Types.h>
#include <AK/Vector.h>
#include <Kernel/API/TimePage.h>
#include <Kernel/Firmware/DeviceTree/DeviceRecipe.h>
#include <Kernel/Forward.h>
#include <Kernel/Library/LockRefPtr.h>
#include <Kernel/UnixTypes.h>
Expand All @@ -38,6 +39,8 @@ class TimeManagement {
static bool is_initialized();
static TimeManagement& the();

static void add_recipe(DeviceTree::DeviceRecipe<NonnullLockRefPtr<HardwareTimerBase>>);

static u64 scheduler_current_time();

static ErrorOr<void> validate_clock_id(clockid_t);
Expand Down

0 comments on commit d6a3500

Please sign in to comment.