From 4d0cb175da7d7edf48a61925c149da30c40d2601 Mon Sep 17 00:00:00 2001 From: Johannes Schlatow Date: Wed, 11 Jan 2023 15:25:25 +0100 Subject: [PATCH] base-hw: use global timer on Cortex A9 genodelabs/genode#4360 --- .../base-hw/lib/mk/spec/cortex_a9/core-hw.inc | 2 +- .../src/core/board/imx6q_sabrelite/board.h | 6 +- .../base-hw/src/core/board/nit6_solox/board.h | 6 +- repos/base-hw/src/core/board/pbxa9/board.h | 2 +- .../base-hw/src/core/board/wand_quad/board.h | 6 +- .../core/spec/arm/cortex_a9_global_timer.cc | 113 +++++++++++++++++ .../core/spec/arm/cortex_a9_global_timer.h | 66 ++++++++++ .../core/spec/arm/cortex_a9_private_timer.cc | 115 ------------------ .../core/spec/arm/cortex_a9_private_timer.h | 60 --------- .../src/include/hw/spec/arm/cortex_a9.h | 6 +- repos/base/include/drivers/defs/pbxa9.h | 4 +- 11 files changed, 195 insertions(+), 191 deletions(-) create mode 100644 repos/base-hw/src/core/spec/arm/cortex_a9_global_timer.cc create mode 100644 repos/base-hw/src/core/spec/arm/cortex_a9_global_timer.h delete mode 100644 repos/base-hw/src/core/spec/arm/cortex_a9_private_timer.cc delete mode 100644 repos/base-hw/src/core/spec/arm/cortex_a9_private_timer.h diff --git a/repos/base-hw/lib/mk/spec/cortex_a9/core-hw.inc b/repos/base-hw/lib/mk/spec/cortex_a9/core-hw.inc index f37baa43cf..44d451997d 100644 --- a/repos/base-hw/lib/mk/spec/cortex_a9/core-hw.inc +++ b/repos/base-hw/lib/mk/spec/cortex_a9/core-hw.inc @@ -7,7 +7,7 @@ # add C++ sources SRC_CC += spec/cortex_a9/board.cc SRC_CC += spec/cortex_a9/cpu.cc -SRC_CC += spec/arm/cortex_a9_private_timer.cc +SRC_CC += spec/arm/cortex_a9_global_timer.cc SRC_CC += spec/arm/gicv2.cc SRC_CC += spec/arm/kernel/lock.cc SRC_CC += kernel/vm_thread_off.cc diff --git a/repos/base-hw/src/core/board/imx6q_sabrelite/board.h b/repos/base-hw/src/core/board/imx6q_sabrelite/board.h index 3e36070a8f..c9128b9346 100644 --- a/repos/base-hw/src/core/board/imx6q_sabrelite/board.h +++ b/repos/base-hw/src/core/board/imx6q_sabrelite/board.h @@ -19,7 +19,7 @@ #include /* base-hw Core includes */ -#include +#include #include namespace Board { @@ -34,8 +34,8 @@ namespace Board { L2_cache & l2_cache(); enum { - CORTEX_A9_PRIVATE_TIMER_CLK = 396000000, /* timer clk runs half the CPU freq */ - CORTEX_A9_PRIVATE_TIMER_DIV = 100, + CORTEX_A9_GLOBAL_TIMER_CLK = 396000000, /* timer clk runs half the CPU freq */ + CORTEX_A9_GLOBAL_TIMER_DIV = 100, }; } diff --git a/repos/base-hw/src/core/board/nit6_solox/board.h b/repos/base-hw/src/core/board/nit6_solox/board.h index f2cff365e8..7ccefd9544 100644 --- a/repos/base-hw/src/core/board/nit6_solox/board.h +++ b/repos/base-hw/src/core/board/nit6_solox/board.h @@ -19,7 +19,7 @@ #include /* base-hw Core includes */ -#include +#include #include namespace Board { @@ -34,8 +34,8 @@ namespace Board { L2_cache & l2_cache(); enum { - CORTEX_A9_PRIVATE_TIMER_CLK = 500000000, /* timer clk runs half the CPU freq */ - CORTEX_A9_PRIVATE_TIMER_DIV = 100, + CORTEX_A9_GLOBAL_TIMER_CLK = 500000000, /* timer clk runs half the CPU freq */ + CORTEX_A9_GLOBAL_TIMER_DIV = 100, }; } diff --git a/repos/base-hw/src/core/board/pbxa9/board.h b/repos/base-hw/src/core/board/pbxa9/board.h index c49d19725e..3b3d914eb1 100644 --- a/repos/base-hw/src/core/board/pbxa9/board.h +++ b/repos/base-hw/src/core/board/pbxa9/board.h @@ -19,7 +19,7 @@ #include /* base-hw Core includes */ -#include +#include #include namespace Board { diff --git a/repos/base-hw/src/core/board/wand_quad/board.h b/repos/base-hw/src/core/board/wand_quad/board.h index 8802e63e08..1689d76fdb 100644 --- a/repos/base-hw/src/core/board/wand_quad/board.h +++ b/repos/base-hw/src/core/board/wand_quad/board.h @@ -20,7 +20,7 @@ #include /* base-hw Core includes */ -#include +#include #include namespace Board { @@ -35,8 +35,8 @@ namespace Board { L2_cache & l2_cache(); enum { - CORTEX_A9_PRIVATE_TIMER_CLK = 500000000, /* timer clk runs half the CPU freq */ - CORTEX_A9_PRIVATE_TIMER_DIV = 100, + CORTEX_A9_GLOBAL_TIMER_CLK = 500000000, /* timer clk runs half the CPU freq */ + CORTEX_A9_GLOBAL_TIMER_DIV = 100, }; } diff --git a/repos/base-hw/src/core/spec/arm/cortex_a9_global_timer.cc b/repos/base-hw/src/core/spec/arm/cortex_a9_global_timer.cc new file mode 100644 index 0000000000..909a78bd60 --- /dev/null +++ b/repos/base-hw/src/core/spec/arm/cortex_a9_global_timer.cc @@ -0,0 +1,113 @@ +/* + * \brief Global timer implementation specific to Cortex A9 + * \author Johannes Schlatow + * \date 2023-01-11 + */ + +/* + * Copyright (C) 2023 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +/* Genode includes */ +#include + +/* core includes */ +#include +#include +#include + +using namespace Genode; +using namespace Kernel; + +using Device = Board::Timer; +using counter_t = Board::Timer::Counter::access_t; + + +enum { + TICS_PER_MS = + Board::CORTEX_A9_GLOBAL_TIMER_CLK / + Board::CORTEX_A9_GLOBAL_TIMER_DIV / 1000, +}; + + +Board::Timer::Timer(unsigned cpu_id) +: + Mmio(Platform::mmio_to_virt(Board::Cpu_mmio::GLOBAL_TIMER_MMIO_BASE)) +{ + enum { PRESCALER = Board::CORTEX_A9_GLOBAL_TIMER_DIV - 1 }; + + static_assert((TICS_PER_MS >= 1000), + "Bad TICS_PER_US value"); + + /* primary CPU sets initial timer value */ + if (cpu_id == 0) { + write(0); + write(0, 0); + write(0, 1); + } + + Control::access_t control = 0; + Control::Irq_enable::set(control, 1); + Control::Prescaler::set(control, PRESCALER); + Control::Timer_enable::set(control, 1); + write(control); +} + + +time_t Board::Timer::current_ticks() const +{ + uint32_t upper = read(1); + uint32_t lower = read(0); + uint32_t upper_new = read(1); + + while (upper != upper_new) { + upper = upper_new; + lower = read(0); + upper_new = read(1); + } + + return (time_t)upper << 32 | (time_t)lower; +} + + +void Timer::_start_one_shot(time_t const ticks) +{ + /* + * First unset the interrupt flag, + * otherwise if the tick is small enough, we loose an interrupt + */ + _device.write(1); + + /* Disable comparator before setting a new value */ + _device.write(0); + + time_t end_ticks = _device.current_ticks() + ticks; + _device.write(end_ticks & 0xFFFFFFFF, 0); + _device.write(end_ticks >> 32 , 1); + + /* Enable comparator before setting a new value */ + _device.write(1); +} + + +time_t Timer::ticks_to_us(time_t const ticks) const { + return timer_ticks_to_us(ticks, TICS_PER_MS); } + + +unsigned Timer::interrupt_id() const { + return Board::Cpu_mmio::GLOBAL_TIMER_IRQ; } + + +time_t Timer::us_to_ticks(time_t const us) const { + return (us / 1000) * TICS_PER_MS; } + + +time_t Timer::_duration() const { + return _device.current_ticks() - _time; } + + +time_t Timer::_max_value() const { + return TICS_PER_MS * 5000; } diff --git a/repos/base-hw/src/core/spec/arm/cortex_a9_global_timer.h b/repos/base-hw/src/core/spec/arm/cortex_a9_global_timer.h new file mode 100644 index 0000000000..d04d4dff4c --- /dev/null +++ b/repos/base-hw/src/core/spec/arm/cortex_a9_global_timer.h @@ -0,0 +1,66 @@ +/* + * \brief Global timer implementation specific to Cortex A9 + * \author Johannes Schlatow + * \date 2023-01-11 + */ + +/* + * Copyright (C) 2023 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _SRC__CORE__SPEC__ARM__CORTEX_A9_GLOBAL_TIMER_H_ +#define _SRC__CORE__SPEC__ARM__CORTEX_A9_GLOBAL_TIMER_H_ + +/* Genode includes */ +#include + +/* base-hw includes */ +#include + +namespace Board { class Timer; } + + +/** + * Timer driver for core + */ +struct Board::Timer : Genode::Mmio +{ + /** + * Counter value registers + */ + struct Counter : Register_array<0x0, 32, 2, 32> { }; + + /** + * Timer control register + */ + struct Control : Register<0x8, 32> + { + struct Timer_enable : Bitfield<0,1> { }; /* enable counting */ + struct Comp_enable : Bitfield<1,1> { }; + struct Irq_enable : Bitfield<2,1> { }; /* unmask interrupt */ + struct Auto_increment : Bitfield<3,1> { }; + struct Prescaler : Bitfield<8,8> { }; + }; + + /** + * Timer interrupt status register + */ + struct Interrupt_status : Register<0xc, 32> + { + struct Event : Bitfield<0,1> { }; /* if counter hit zero */ + }; + + /** + * Comparator registers + */ + struct Comparator : Register_array<0x10, 32, 2, 32> { }; + + Kernel::time_t current_ticks() const; + + Timer(unsigned); +}; + +#endif /* _SRC__CORE__SPEC__ARM__CORTEX_A9_GLOBAL_TIMER_H_ */ diff --git a/repos/base-hw/src/core/spec/arm/cortex_a9_private_timer.cc b/repos/base-hw/src/core/spec/arm/cortex_a9_private_timer.cc deleted file mode 100644 index d2bf7dc4b4..0000000000 --- a/repos/base-hw/src/core/spec/arm/cortex_a9_private_timer.cc +++ /dev/null @@ -1,115 +0,0 @@ -/* - * \brief Timer implementation specific to Cortex A9 - * \author Stefan Kalkowski - * \author Martin Stein - * \date 2016-01-07 - */ - -/* - * Copyright (C) 2016-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -/* Genode includes */ -#include - -/* core includes */ -#include -#include -#include - -using namespace Genode; -using namespace Kernel; - -using Device = Board::Timer; -using counter_t = Board::Timer::Counter::access_t; - - -enum { - TICS_PER_MS = - Board::CORTEX_A9_PRIVATE_TIMER_CLK / - Board::CORTEX_A9_PRIVATE_TIMER_DIV / 1000, - - MAX_COUNTER_VAL = ~(counter_t)0 -}; - - -Board::Timer::Timer(unsigned) -: - Mmio(Platform::mmio_to_virt(Board::Cpu_mmio::PRIVATE_TIMER_MMIO_BASE)) -{ - enum { PRESCALER = Board::CORTEX_A9_PRIVATE_TIMER_DIV - 1 }; - - static_assert((TICS_PER_MS >= 1000) /*&& - (TICS_PER_US * 1000000 * - Board::CORTEX_A9_PRIVATE_TIMER_DIV) == - Board::CORTEX_A9_PRIVATE_TIMER_CLK*/, - "Bad TICS_PER_US value"); - - write(0xffffffff); - Control::access_t control = 0; - Control::Irq_enable::set(control, 1); - Control::Prescaler::set(control, PRESCALER); - Control::Auto_reload::set(control, 1); - Control::Timer_enable::set(control, 1); - write(control); -} - - -void Timer::_start_one_shot(time_t const ticks) -{ - /* - * First unset the interrupt flag, - * otherwise if the tick is small enough, we loose an interrupt - */ - _device.write(1); - _device.write(ticks); -} - - -time_t Timer::ticks_to_us(time_t const ticks) const { - return timer_ticks_to_us(ticks, TICS_PER_MS); } - - -unsigned Timer::interrupt_id() const { - return Board::Cpu_mmio::PRIVATE_TIMER_IRQ; } - - -time_t Timer::us_to_ticks(time_t const us) const { - return (us / 1000) * TICS_PER_MS; } - - -time_t Timer::_duration() const -{ - counter_t const start_counter_val { (counter_t)_last_timeout_duration }; - counter_t const curr_counter_val { _device.read() }; - - /* - * Calculate result depending on whether the counter already wrapped or - * not. See the comment in the implementation of '_max_value' for an - * explanation why this comparison is done instead of checking the IRQ - * status and why it is sufficient. - */ - if (curr_counter_val > start_counter_val) - return start_counter_val + (MAX_COUNTER_VAL - curr_counter_val); - - return start_counter_val - curr_counter_val; -} - - -time_t Timer::_max_value() const -{ - /* - * We propagate a max timeout value far lower than the one required - * by the hardware. This is because on some platforms (Qemu 4.2.1 PBXA9), - * the IRQ status register is not reliable. Sometimes, it indicates an IRQ - * too early, i.e., shortly before the counter wraps. Therefore we have to - * accomplish wrap detection via counter comparison only. Therefore, we - * have to make sure that we always read out the counter before it hits - * the max timout value again. And, therefore, the max timeout value has - * to be far away from the first value the counter has after wrapping. - */ - return MAX_COUNTER_VAL >> 1; -} diff --git a/repos/base-hw/src/core/spec/arm/cortex_a9_private_timer.h b/repos/base-hw/src/core/spec/arm/cortex_a9_private_timer.h deleted file mode 100644 index 45ca3d4768..0000000000 --- a/repos/base-hw/src/core/spec/arm/cortex_a9_private_timer.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * \brief Private Timer implementation specific to Cortex A9 - * \author Martin stein - * \date 2011-12-13 - */ - -/* - * Copyright (C) 2011-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _SRC__CORE__SPEC__ARM__CORTEX_A9_PRIVATE_TIMER_H_ -#define _SRC__CORE__SPEC__ARM__CORTEX_A9_PRIVATE_TIMER_H_ - -/* Genode includes */ -#include - -namespace Board { class Timer; } - - -/** - * Timer driver for core - */ -struct Board::Timer : Genode::Mmio -{ - /** - * Load value register - */ - struct Load : Register<0x0, 32> { }; - - /** - * Counter value register - */ - struct Counter : Register<0x4, 32> { }; - - /** - * Timer control register - */ - struct Control : Register<0x8, 32> - { - struct Timer_enable : Bitfield<0,1> { }; /* enable counting */ - struct Auto_reload : Bitfield<1,1> { }; - struct Irq_enable : Bitfield<2,1> { }; /* unmask interrupt */ - struct Prescaler : Bitfield<8,8> { }; - }; - - /** - * Timer interrupt status register - */ - struct Interrupt_status : Register<0xc, 32> - { - struct Event : Bitfield<0,1> { }; /* if counter hit zero */ - }; - - Timer(unsigned); -}; - -#endif /* _SRC__CORE__SPEC__ARM__CORTEX_A9_PRIVATE_TIMER_H_ */ diff --git a/repos/base-hw/src/include/hw/spec/arm/cortex_a9.h b/repos/base-hw/src/include/hw/spec/arm/cortex_a9.h index dd2dbd3356..be9099f8c6 100644 --- a/repos/base-hw/src/include/hw/spec/arm/cortex_a9.h +++ b/repos/base-hw/src/include/hw/spec/arm/cortex_a9.h @@ -30,9 +30,9 @@ struct Hw::Cortex_a9_mmio IRQ_CONTROLLER_CPU_BASE = BASE + 0x100, IRQ_CONTROLLER_CPU_SIZE = 0x100, - PRIVATE_TIMER_MMIO_BASE = BASE + 0x600, - PRIVATE_TIMER_MMIO_SIZE = 0x10, - PRIVATE_TIMER_IRQ = 29, + GLOBAL_TIMER_MMIO_BASE = BASE + 0x200, + GLOBAL_TIMER_MMIO_SIZE = 0x18, + GLOBAL_TIMER_IRQ = 27, }; }; diff --git a/repos/base/include/drivers/defs/pbxa9.h b/repos/base/include/drivers/defs/pbxa9.h index 6b5dd30609..0ca1e146e6 100644 --- a/repos/base/include/drivers/defs/pbxa9.h +++ b/repos/base/include/drivers/defs/pbxa9.h @@ -43,8 +43,8 @@ namespace Pbxa9 { SYSTEM_CONTROL_MMIO_BASE = 0x10000000, /* CPU */ - CORTEX_A9_PRIVATE_TIMER_CLK = 100000000, - CORTEX_A9_PRIVATE_TIMER_DIV = 100, + CORTEX_A9_GLOBAL_TIMER_CLK = 100000000, + CORTEX_A9_GLOBAL_TIMER_DIV = 100, CORTEX_A9_PRIVATE_MEM_BASE = 0x1f000000, CORTEX_A9_PRIVATE_MEM_SIZE = 0x2000,