2a9a653b2b
fix #652
271 lines
5.6 KiB
C++
271 lines
5.6 KiB
C++
/*
|
|
* \brief Basic driver behind platform timer
|
|
* \author Martin Stein
|
|
* \date 2012-05-03
|
|
*/
|
|
|
|
/*
|
|
* Copyright (C) 2012-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__OMAP4__PLATFORM_TIMER_BASE_H_
|
|
#define _HW__OMAP4__PLATFORM_TIMER_BASE_H_
|
|
|
|
/* Genode includes */
|
|
#include <io_mem_session/connection.h>
|
|
#include <util/mmio.h>
|
|
#include <irq_session/connection.h>
|
|
#include <drivers/board_base.h>
|
|
|
|
namespace Genode
|
|
{
|
|
/**
|
|
* Omap4 general purpose timer 3 through 9 and 11
|
|
*/
|
|
class Omap4_gp_timer_1 : public Mmio
|
|
{
|
|
/**
|
|
* Timer tics per microsecond
|
|
*/
|
|
static float tics_per_us() {
|
|
return (float)Board_base::SYS_CLK / 1000000; }
|
|
|
|
/**
|
|
* Microsecodns per timer tic
|
|
*/
|
|
static float us_per_tic() { return 1 / tics_per_us(); }
|
|
|
|
/**
|
|
* L4 interface control
|
|
*/
|
|
struct Tiocp_cfg : Register<0x10, 32>
|
|
{
|
|
struct Softreset : Bitfield<0, 1> { }; /* SW reset active */
|
|
struct Idlemode : Bitfield<2, 2> /* action on IDLE request */
|
|
{
|
|
enum { FORCE_IDLE = 0 };
|
|
};
|
|
};
|
|
|
|
/**
|
|
* Timer wake-up enable register
|
|
*/
|
|
struct Twer : Register<0x20, 32>
|
|
{
|
|
struct Mat_wup_ena : Bitfield<0, 1> { }; /* wakeup on match */
|
|
struct Ovf_wup_ena : Bitfield<1, 1> { }; /* wakeup on overflow */
|
|
struct Tcar_wup_ena : Bitfield<2, 1> { }; /* wakeup on capture */
|
|
|
|
/**
|
|
* Timer initialization value
|
|
*/
|
|
static access_t init_timer()
|
|
{
|
|
return Mat_wup_ena::bits(0) |
|
|
Ovf_wup_ena::bits(0) |
|
|
Tcar_wup_ena::bits(0);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Timer synchronous interface control register
|
|
*/
|
|
struct Tsicr : Register<0x54, 32>
|
|
{
|
|
struct Posted : Bitfield<2, 1> { }; /* enable posted mode */
|
|
};
|
|
|
|
/**
|
|
* Control timer-functionality dependent features
|
|
*/
|
|
struct Tclr : Register<0x38, 32>
|
|
{
|
|
struct St : Bitfield<0, 1> { }; /* start/stop timer */
|
|
struct Ar : Bitfield<1, 1> { }; /* enable eutoreload */
|
|
struct Pre : Bitfield<5, 1> { }; /* enable prescaler */
|
|
|
|
/**
|
|
* Run-and-wrap configuration
|
|
*/
|
|
static access_t init_run_and_wrap()
|
|
{
|
|
return St::bits(0) |
|
|
Ar::bits(1) |
|
|
Pre::bits(0);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Set IRQ enables
|
|
*/
|
|
struct Irqenable_set : Register<0x2c, 32>
|
|
{
|
|
struct Ovf_en_flag : Bitfield<1, 1> { }; /* enable overflow IRQ */
|
|
};
|
|
|
|
/**
|
|
* IRQ status
|
|
*/
|
|
struct Irqstatus : Register<0x28, 32>
|
|
{
|
|
struct Ovf_it_flag : Bitfield<1, 1> { }; /* clear overflow IRQ */
|
|
};
|
|
|
|
/**
|
|
* Timer counter register
|
|
*/
|
|
struct Tcrr : Register<0x3c, 32>
|
|
{
|
|
/**
|
|
* maximum counter value
|
|
*/
|
|
static access_t max_value() { return ~0; }
|
|
};
|
|
|
|
/**
|
|
* Timer load value register
|
|
*/
|
|
struct Tldr : Register<0x40, 32> { };
|
|
|
|
/**
|
|
* Freeze timer counter
|
|
*/
|
|
void _freeze() { write<Tclr::St>(0); }
|
|
|
|
/**
|
|
* Unfreeze timer counter
|
|
*/
|
|
void _unfreeze() { write<Tclr::St>(1); }
|
|
|
|
/**
|
|
* Get remaining counting amount
|
|
*/
|
|
unsigned long _value() const { return max_value() - read<Tcrr>(); }
|
|
|
|
/**
|
|
* Apply counting amount
|
|
*/
|
|
void _value(unsigned long const v) { write<Tcrr>(max_value() - v); }
|
|
|
|
public:
|
|
|
|
/**
|
|
* Constructor
|
|
*
|
|
* \param base MMIO base
|
|
*/
|
|
Omap4_gp_timer_1(addr_t const base) : Mmio(base)
|
|
{
|
|
_freeze();
|
|
|
|
/* do a software reset */
|
|
write<Tiocp_cfg::Softreset>(1);
|
|
while (read<Tiocp_cfg::Softreset>()) ;
|
|
|
|
/* configure Idle mode */
|
|
write<Tiocp_cfg::Idlemode>(Tiocp_cfg::Idlemode::FORCE_IDLE);
|
|
|
|
/* enable wake-up interrupt events */
|
|
write<Twer>(Twer::init_timer());
|
|
|
|
/* select posted mode */
|
|
write<Tsicr::Posted>(0);
|
|
}
|
|
|
|
/**
|
|
* Count down 'value', raise IRQ output, wrap counter and continue
|
|
*/
|
|
void run_and_wrap(unsigned long value)
|
|
{
|
|
enum { MIN_VALUE = 1 };
|
|
|
|
/* stop timer */
|
|
_freeze();
|
|
clear_interrupt();
|
|
value = value ? value : MIN_VALUE;
|
|
|
|
/* configure for a run and wrap */
|
|
write<Tclr>(Tclr::init_run_and_wrap());
|
|
write<Irqenable_set::Ovf_en_flag>(1);
|
|
|
|
/* install value */
|
|
_value(value);
|
|
write<Tldr>(0);
|
|
|
|
/* start timer */
|
|
_unfreeze();
|
|
}
|
|
|
|
/**
|
|
* Clear interrupt output
|
|
*/
|
|
void clear_interrupt() {
|
|
write<Irqstatus::Ovf_it_flag>(1); }
|
|
|
|
/**
|
|
* Maximum timeout value
|
|
*/
|
|
unsigned long max_value() const { return Tcrr::max_value(); }
|
|
|
|
/**
|
|
* 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
|
|
{
|
|
Tcrr::access_t const v = _value();
|
|
wrapped = (bool)read<Irqstatus::Ovf_it_flag>();
|
|
return wrapped ? _value() : v;
|
|
}
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Basic driver behind platform timer
|
|
*/
|
|
class Platform_timer_base : public Genode::Io_mem_connection,
|
|
public Genode::Omap4_gp_timer_1
|
|
{
|
|
/* FIXME these should be located in a omap4-defs file */
|
|
enum {
|
|
GP_TIMER_3_IRQ = 71,
|
|
GP_TIMER_3_MMIO_BASE = 0x48034000,
|
|
GP_TIMER_3_MMIO_SIZE = 0x00001000,
|
|
};
|
|
|
|
public:
|
|
|
|
enum { IRQ = GP_TIMER_3_IRQ };
|
|
|
|
/**
|
|
* Constructor
|
|
*/
|
|
Platform_timer_base() :
|
|
Io_mem_connection(GP_TIMER_3_MMIO_BASE, GP_TIMER_3_MMIO_SIZE),
|
|
Genode::Omap4_gp_timer_1((Genode::addr_t)Genode::env()->rm_session()->attach(dataspace()))
|
|
{ }
|
|
};
|
|
|
|
#endif /* _HW__OMAP4__PLATFORM_TIMER_BASE_H_ */
|
|
|