From a0d182e25ab42ec3bd8ceb812dab3685375504ff Mon Sep 17 00:00:00 2001 From: Martin Stein Date: Thu, 4 Apr 2013 16:22:15 +0200 Subject: [PATCH] hw_arndale: userland timer driver Ref #706 --- base-hw/src/core/arndale/platform_support.cc | 1 + os/lib/mk/hw_arndale/timer.mk | 3 + .../timer/hw/exynos5/platform_timer_base.h | 211 ++++++++++++++++++ 3 files changed, 215 insertions(+) create mode 100644 os/lib/mk/hw_arndale/timer.mk create mode 100644 os/src/drivers/timer/hw/exynos5/platform_timer_base.h diff --git a/base-hw/src/core/arndale/platform_support.cc b/base-hw/src/core/arndale/platform_support.cc index 5ea6066e8..91a49409f 100644 --- a/base-hw/src/core/arndale/platform_support.cc +++ b/base-hw/src/core/arndale/platform_support.cc @@ -66,6 +66,7 @@ Native_region * Platform::_core_only_mmio_regions(unsigned const i) static Native_region _regions[] = { { Board::GIC_CPU_MMIO_BASE, Board::GIC_CPU_MMIO_SIZE }, + { Board::MCT_MMIO_BASE, Board::MCT_MMIO_SIZE }, }; return i < sizeof(_regions)/sizeof(_regions[0]) ? &_regions[i] : 0; } diff --git a/os/lib/mk/hw_arndale/timer.mk b/os/lib/mk/hw_arndale/timer.mk new file mode 100644 index 000000000..889ed2d31 --- /dev/null +++ b/os/lib/mk/hw_arndale/timer.mk @@ -0,0 +1,3 @@ +INC_DIR += $(REP_DIR)/src/drivers/timer/hw $(REP_DIR)/src/drivers/timer/hw/exynos5 + +include $(REP_DIR)/lib/mk/timer.inc diff --git a/os/src/drivers/timer/hw/exynos5/platform_timer_base.h b/os/src/drivers/timer/hw/exynos5/platform_timer_base.h new file mode 100644 index 000000000..0f36ec008 --- /dev/null +++ b/os/src/drivers/timer/hw/exynos5/platform_timer_base.h @@ -0,0 +1,211 @@ +/* + * \brief Basic driver behind platform timer + * \author Martin stein + * \date 2013-04-04 + */ + +/* + * Copyright (C) 2013 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +#ifndef _HW__EXYNOS5__PLATFORM_TIMER_BASE_H_ +#define _HW__EXYNOS5__PLATFORM_TIMER_BASE_H_ + +/* Genode includes */ +#include +#include +#include +#include + +namespace Genode +{ + /** + * Exynos 5250 pulse width modulation timer + */ + class Pwm : public Mmio + { + enum { PRESCALER = 2 }; + + /** + * Timer configuration 0 + */ + struct Cfg0 : Register<0x0, 32> + { + struct Prescaler0 : Bitfield<0, 8> + { + enum { DEFAULT = PRESCALER - 1 }; + }; + }; + + /** + * Timer configuration 1 + */ + struct Cfg1 : Register<0x4, 32> + { + struct Div0 : Bitfield<0, 4> { enum { DISABLE = 0 }; }; + }; + + /** + * Timer control + */ + struct Con : Register<0x8, 32> + { + struct Enable0 : Bitfield<0, 1> { }; + struct Update0 : Bitfield<1, 1> { }; + struct Invert_tout0 : Bitfield<2, 1> { }; + struct Auto_reload0 : Bitfield<3, 1> { }; + struct Deadzone_en : Bitfield<4, 1> { }; + + /** + * Initialization value + */ + static access_t init_value() + { + return Invert_tout0::bits(0) | + Auto_reload0::bits(1) | + Deadzone_en::bits(0); + } + }; + + /** + * Timer 0 count buffer + */ + struct Cntb0 : Register<0xc, 32> { }; + + /** + * Timer 0 compare buffer + */ + struct Cmpb0 : Register<0x10, 32> { }; + + /** + * Timer 0 count observation + */ + struct Cnto0 : Register<0x14, 32> { }; + + /** + * Timer IRQ control and status + */ + struct Int : Register<0x44, 32> + { + struct En0 : Bitfield<0, 1> { }; + struct En1 : Bitfield<1, 1> { }; + struct En2 : Bitfield<2, 1> { }; + struct En3 : Bitfield<3, 1> { }; + struct En4 : Bitfield<4, 1> { }; + struct Stat0 : Bitfield<5, 1> { }; + + /** + * Initialization value + */ + static access_t init_value() + { + return En0::bits(1) | + En1::bits(0) | + En2::bits(0) | + En3::bits(0) | + En4::bits(0); + } + }; + + /** + * Timer tics per microsecond + */ + static float tics_per_us() { + return (float)Board_base::PWM_CLOCK / PRESCALER / 1000 / 1000; } + + /** + * Microseconds per timer tic + */ + static float us_per_tic() { return (float)1 / tics_per_us(); } + + public: + + /** + * Constructor + * + * \param base MMIO base + */ + Pwm(addr_t const base) : Mmio(base) + { + write(Cfg0::Prescaler0::DEFAULT); + write(Cfg1::Div0::DISABLE); + write(Int::init_value()); + write(Con::init_value()); + write(0); + } + + /** + * Count down 'value', raise IRQ output, wrap counter and continue + */ + void run_and_wrap(unsigned long value) + { + write(value); + write(0); + write(1); + write(0); + write(1); + write(max_value()); + write(1); + } + + /** + * Maximum timeout value + */ + unsigned long max_value() const { return (Cntb0::access_t)~0; } + + /** + * Translate timer tics to microseconds + */ + unsigned long tics_to_us(unsigned long const tics) const + { + float const us = tics * us_per_tic(); + return (unsigned long)us; + } + + /** + * Translate microseconds to timer tics + */ + unsigned long us_to_tics(unsigned long const us) + { + float const tics = us * tics_per_us(); + return (unsigned long)tics; + } + + /** + * Sample the timer counter and according wrapped status + */ + unsigned long value(bool & wrapped) const + { + unsigned long v = read(); + wrapped = (bool)read(); + return wrapped ? read() : v; + } + }; +} + +/** + * Basic driver behind platform timer + */ +class Platform_timer_base : public Genode::Io_mem_connection, + public Genode::Pwm +{ + public: + + enum { IRQ = Genode::Board_base::PWM_IRQ_0 }; + + /** + * Constructor + */ + Platform_timer_base() + : Io_mem_connection(Genode::Board_base::PWM_MMIO_BASE, + Genode::Board_base::PWM_MMIO_SIZE), + Genode::Pwm((Genode::addr_t)Genode::env()->rm_session() + ->attach(dataspace())) + { } +}; + +#endif /* _HW__EXYNOS5__PLATFORM_TIMER_BASE_H_ */ +