mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-21 06:33:31 +00:00
parent
777b093cad
commit
4d0cb175da
@ -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
|
||||
|
@ -19,7 +19,7 @@
|
||||
#include <hw/spec/arm/imx6q_sabrelite_board.h>
|
||||
|
||||
/* base-hw Core includes */
|
||||
#include <spec/arm/cortex_a9_private_timer.h>
|
||||
#include <spec/arm/cortex_a9_global_timer.h>
|
||||
#include <spec/cortex_a9/cpu.h>
|
||||
|
||||
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,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -19,7 +19,7 @@
|
||||
#include <hw/spec/arm/nit6_solox_board.h>
|
||||
|
||||
/* base-hw Core includes */
|
||||
#include <spec/arm/cortex_a9_private_timer.h>
|
||||
#include <spec/arm/cortex_a9_global_timer.h>
|
||||
#include <spec/cortex_a9/cpu.h>
|
||||
|
||||
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,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -19,7 +19,7 @@
|
||||
#include <hw/spec/arm/pbxa9_board.h>
|
||||
|
||||
/* base-hw Core includes */
|
||||
#include <spec/arm/cortex_a9_private_timer.h>
|
||||
#include <spec/arm/cortex_a9_global_timer.h>
|
||||
#include <spec/cortex_a9/cpu.h>
|
||||
|
||||
namespace Board {
|
||||
|
@ -20,7 +20,7 @@
|
||||
#include <hw/spec/arm/wand_quad_board.h>
|
||||
|
||||
/* base-hw Core includes */
|
||||
#include <spec/arm/cortex_a9_private_timer.h>
|
||||
#include <spec/arm/cortex_a9_global_timer.h>
|
||||
#include <spec/cortex_a9/cpu.h>
|
||||
|
||||
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,
|
||||
};
|
||||
}
|
||||
|
||||
|
113
repos/base-hw/src/core/spec/arm/cortex_a9_global_timer.cc
Normal file
113
repos/base-hw/src/core/spec/arm/cortex_a9_global_timer.cc
Normal file
@ -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 <drivers/timer/util.h>
|
||||
|
||||
/* core includes */
|
||||
#include <kernel/cpu.h>
|
||||
#include <kernel/timer.h>
|
||||
#include <platform.h>
|
||||
|
||||
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<Control::Timer_enable>(0);
|
||||
write<Counter>(0, 0);
|
||||
write<Counter>(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>(control);
|
||||
}
|
||||
|
||||
|
||||
time_t Board::Timer::current_ticks() const
|
||||
{
|
||||
uint32_t upper = read<Counter>(1);
|
||||
uint32_t lower = read<Counter>(0);
|
||||
uint32_t upper_new = read<Counter>(1);
|
||||
|
||||
while (upper != upper_new) {
|
||||
upper = upper_new;
|
||||
lower = read<Counter>(0);
|
||||
upper_new = read<Counter>(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<Device::Interrupt_status::Event>(1);
|
||||
|
||||
/* Disable comparator before setting a new value */
|
||||
_device.write<Device::Control::Comp_enable>(0);
|
||||
|
||||
time_t end_ticks = _device.current_ticks() + ticks;
|
||||
_device.write<Device::Comparator>(end_ticks & 0xFFFFFFFF, 0);
|
||||
_device.write<Device::Comparator>(end_ticks >> 32 , 1);
|
||||
|
||||
/* Enable comparator before setting a new value */
|
||||
_device.write<Device::Control::Comp_enable>(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; }
|
66
repos/base-hw/src/core/spec/arm/cortex_a9_global_timer.h
Normal file
66
repos/base-hw/src/core/spec/arm/cortex_a9_global_timer.h
Normal file
@ -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 <util/mmio.h>
|
||||
|
||||
/* base-hw includes */
|
||||
#include <kernel/types.h>
|
||||
|
||||
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_ */
|
@ -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 <drivers/timer/util.h>
|
||||
|
||||
/* core includes */
|
||||
#include <kernel/cpu.h>
|
||||
#include <kernel/timer.h>
|
||||
#include <platform.h>
|
||||
|
||||
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<Load>(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>(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<Device::Interrupt_status::Event>(1);
|
||||
_device.write<Device::Counter>(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<Device::Counter>() };
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
@ -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 <util/mmio.h>
|
||||
|
||||
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_ */
|
@ -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,
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -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,
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user