mirror of
https://github.com/apache/nuttx.git
synced 2026-05-30 13:27:01 +08:00
arch/arm: Add clkdev driver for generic timer.
This commit added clkdev driver for arm generic timer. Signed-off-by: ouyangxiangzhen <ouyangxiangzhen@xiaomi.com>
This commit is contained in:
committed by
Xiang Xiao
parent
d335cce43a
commit
996f110925
@@ -1134,6 +1134,7 @@ config ARCH_ARMV8R
|
|||||||
select ARCH_HAVE_CPUINFO
|
select ARCH_HAVE_CPUINFO
|
||||||
select ARCH_HAVE_PERF_EVENTS
|
select ARCH_HAVE_PERF_EVENTS
|
||||||
select ONESHOT
|
select ONESHOT
|
||||||
|
select ONESHOT_COUNT
|
||||||
select ALARM_ARCH
|
select ALARM_ARCH
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -51,6 +51,9 @@ config ARMV7A_HAVE_GTM
|
|||||||
config ARMV7A_HAVE_PTM
|
config ARMV7A_HAVE_PTM
|
||||||
bool
|
bool
|
||||||
default n
|
default n
|
||||||
|
select ONESHOT
|
||||||
|
select ONESHOT_COUNT
|
||||||
|
select ONESHOT_FAST_DIVISION
|
||||||
---help---
|
---help---
|
||||||
Selected by the configuration tool if the architecture supports the
|
Selected by the configuration tool if the architecture supports the
|
||||||
per-processor Private Timers (PTMs)
|
per-processor Private Timers (PTMs)
|
||||||
|
|||||||
@@ -50,52 +50,6 @@
|
|||||||
# define GIC_IRQ_TIMER GIC_IRQ_PTM
|
# define GIC_IRQ_TIMER GIC_IRQ_PTM
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
* Private Types
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
/* This structure provides the private representation of the "lower-half"
|
|
||||||
* driver state structure. This structure must be cast-compatible with the
|
|
||||||
* oneshot_lowerhalf_s structure.
|
|
||||||
*/
|
|
||||||
|
|
||||||
struct arm_timer_lowerhalf_s
|
|
||||||
{
|
|
||||||
struct oneshot_lowerhalf_s lh; /* Lower half operations */
|
|
||||||
uint32_t freq; /* Timer working clock frequency(Hz) */
|
|
||||||
|
|
||||||
/* which cpu timer is running, -1 indicate timer stoppd */
|
|
||||||
|
|
||||||
int running;
|
|
||||||
};
|
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
* Private Function Prototypes
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
static int arm_timer_maxdelay(struct oneshot_lowerhalf_s *lower,
|
|
||||||
struct timespec *ts);
|
|
||||||
static int arm_timer_start(struct oneshot_lowerhalf_s *lower,
|
|
||||||
const struct timespec *ts);
|
|
||||||
static int arm_timer_cancel(struct oneshot_lowerhalf_s *lower,
|
|
||||||
struct timespec *ts);
|
|
||||||
static int arm_timer_current(struct oneshot_lowerhalf_s *lower,
|
|
||||||
struct timespec *ts);
|
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
* Private Data
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
static const struct oneshot_operations_s g_arm_timer_ops =
|
|
||||||
{
|
|
||||||
.max_delay = arm_timer_maxdelay,
|
|
||||||
.start = arm_timer_start,
|
|
||||||
.cancel = arm_timer_cancel,
|
|
||||||
.current = arm_timer_current,
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct arm_timer_lowerhalf_s g_arm_timer_lowerhalf;
|
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Private Functions
|
* Private Functions
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
@@ -103,6 +57,7 @@ static struct arm_timer_lowerhalf_s g_arm_timer_lowerhalf;
|
|||||||
static inline void arm_timer_set_freq(uint32_t freq)
|
static inline void arm_timer_set_freq(uint32_t freq)
|
||||||
{
|
{
|
||||||
CP15_SET(CNTFRQ, freq);
|
CP15_SET(CNTFRQ, freq);
|
||||||
|
UP_ISB();
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint64_t arm_timer_phy_count(void)
|
static inline uint64_t arm_timer_phy_count(void)
|
||||||
@@ -124,118 +79,54 @@ static inline void arm_timer_phy_enable(bool enable)
|
|||||||
{
|
{
|
||||||
CP15_MODIFY((uint32_t)enable << CNT_CTL_ENABLE_BIT,
|
CP15_MODIFY((uint32_t)enable << CNT_CTL_ENABLE_BIT,
|
||||||
BIT(CNT_CTL_ENABLE_BIT), CNTP_CTL);
|
BIT(CNT_CTL_ENABLE_BIT), CNTP_CTL);
|
||||||
|
UP_ISB();
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void arm_timer_phy_set_irq_mask(bool mask)
|
static inline void arm_timer_phy_set_irq_mask(bool mask)
|
||||||
{
|
{
|
||||||
CP15_MODIFY((uint32_t)mask << CNT_CTL_IMASK_BIT,
|
CP15_MODIFY((uint32_t)mask << CNT_CTL_IMASK_BIT,
|
||||||
BIT(CNT_CTL_IMASK_BIT), CNTP_CTL);
|
BIT(CNT_CTL_IMASK_BIT), CNTP_CTL);
|
||||||
|
UP_ISB();
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void arm_timer_virt_set_irq_mask(bool mask)
|
static int arm_timer_interrupt(int irq, void *regs, void *arg)
|
||||||
{
|
{
|
||||||
CP15_MODIFY((uint32_t)mask << CNT_CTL_IMASK_BIT,
|
struct oneshot_lowerhalf_s *priv = (struct oneshot_lowerhalf_s *)arg;
|
||||||
BIT(CNT_CTL_IMASK_BIT), CNTV_CTL);
|
|
||||||
|
arm_timer_phy_set_absolute(UINT64_MAX);
|
||||||
|
|
||||||
|
oneshot_process_callback(priv);
|
||||||
|
|
||||||
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint64_t nsec_from_count(uint64_t count, uint32_t freq)
|
static clkcnt_t arm_oneshot_max_delay(struct oneshot_lowerhalf_s *lower)
|
||||||
{
|
{
|
||||||
uint64_t sec = count / freq;
|
return UINT32_MAX;
|
||||||
uint64_t nsec = (count % freq) * NSEC_PER_SEC / freq;
|
|
||||||
return sec * NSEC_PER_SEC + nsec;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint64_t nsec_to_count(uint32_t nsec, uint32_t freq)
|
static clkcnt_t arm_oneshot_current(struct oneshot_lowerhalf_s *lower)
|
||||||
{
|
{
|
||||||
return (uint64_t)nsec * freq / NSEC_PER_SEC;
|
/* We do not need memory barrier here. */
|
||||||
|
|
||||||
|
return arm_timer_phy_count();
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint64_t sec_to_count(uint32_t sec, uint32_t freq)
|
static void arm_oneshot_start_absolute(struct oneshot_lowerhalf_s *lower,
|
||||||
|
clkcnt_t expected)
|
||||||
{
|
{
|
||||||
return (uint64_t)sec * freq;
|
arm_timer_phy_set_absolute(expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int arm_timer_maxdelay(struct oneshot_lowerhalf_s *lower_,
|
static void arm_oneshot_start(struct oneshot_lowerhalf_s *lower,
|
||||||
struct timespec *ts)
|
clkcnt_t delta)
|
||||||
{
|
{
|
||||||
uint64_t maxnsec = nsec_from_count(UINT64_MAX, arm_timer_get_freq());
|
arm_timer_phy_set_relative(delta);
|
||||||
|
|
||||||
ts->tv_sec = maxnsec / NSEC_PER_SEC;
|
|
||||||
ts->tv_nsec = maxnsec % NSEC_PER_SEC;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int arm_timer_start(struct oneshot_lowerhalf_s *lower_,
|
static void arm_oneshot_cancel(struct oneshot_lowerhalf_s *lower)
|
||||||
const struct timespec *ts)
|
|
||||||
{
|
{
|
||||||
struct arm_timer_lowerhalf_s *lower =
|
arm_timer_phy_set_absolute(UINT64_MAX);
|
||||||
(struct arm_timer_lowerhalf_s *)lower_;
|
|
||||||
irqstate_t flags;
|
|
||||||
uint64_t count;
|
|
||||||
|
|
||||||
flags = up_irq_save();
|
|
||||||
|
|
||||||
lower->running = this_cpu();
|
|
||||||
|
|
||||||
count = sec_to_count(ts->tv_sec, lower->freq) +
|
|
||||||
nsec_to_count(ts->tv_nsec, lower->freq);
|
|
||||||
|
|
||||||
arm_timer_phy_set_relative(count > UINT32_MAX ? UINT32_MAX : count);
|
|
||||||
|
|
||||||
arm_timer_phy_set_irq_mask(false);
|
|
||||||
|
|
||||||
up_irq_restore(flags);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int arm_timer_cancel(struct oneshot_lowerhalf_s *lower_,
|
|
||||||
struct timespec *ts)
|
|
||||||
{
|
|
||||||
struct arm_timer_lowerhalf_s *lower =
|
|
||||||
(struct arm_timer_lowerhalf_s *)lower_;
|
|
||||||
irqstate_t flags;
|
|
||||||
|
|
||||||
flags = up_irq_save();
|
|
||||||
|
|
||||||
lower->running = -1;
|
|
||||||
|
|
||||||
arm_timer_phy_set_irq_mask(true);
|
|
||||||
|
|
||||||
up_irq_restore(flags);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int arm_timer_current(struct oneshot_lowerhalf_s *lower_,
|
|
||||||
struct timespec *ts)
|
|
||||||
{
|
|
||||||
struct arm_timer_lowerhalf_s *lower =
|
|
||||||
(struct arm_timer_lowerhalf_s *)lower_;
|
|
||||||
uint64_t nsec = nsec_from_count(arm_timer_phy_count(),
|
|
||||||
lower->freq);
|
|
||||||
|
|
||||||
ts->tv_sec = nsec / NSEC_PER_SEC;
|
|
||||||
ts->tv_nsec = nsec % NSEC_PER_SEC;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int arm_timer_interrupt(int irq, void *context, void *arg)
|
|
||||||
{
|
|
||||||
struct arm_timer_lowerhalf_s *lower = arg;
|
|
||||||
|
|
||||||
DEBUGASSERT(lower != NULL);
|
|
||||||
|
|
||||||
arm_timer_phy_set_irq_mask(true);
|
|
||||||
|
|
||||||
if (lower->running == this_cpu())
|
|
||||||
{
|
|
||||||
oneshot_process_callback(&lower->lh);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void arm_timer_initialize_per_cpu(unsigned int freq)
|
static void arm_timer_initialize_per_cpu(unsigned int freq)
|
||||||
@@ -247,29 +138,50 @@ static void arm_timer_initialize_per_cpu(unsigned int freq)
|
|||||||
arm_timer_set_freq(freq);
|
arm_timer_set_freq(freq);
|
||||||
}
|
}
|
||||||
|
|
||||||
arm_timer_phy_set_irq_mask(true);
|
arm_timer_phy_set_absolute(UINT64_MAX);
|
||||||
arm_timer_phy_enable(true);
|
arm_timer_phy_enable(true);
|
||||||
|
arm_timer_phy_set_irq_mask(false);
|
||||||
|
|
||||||
up_enable_irq(GIC_IRQ_TIMER);
|
up_enable_irq(GIC_IRQ_TIMER);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/****************************************************************************
|
||||||
|
* Private Data
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
static const struct oneshot_operations_s g_arm_oneshot_ops =
|
||||||
|
{
|
||||||
|
.current = arm_oneshot_current,
|
||||||
|
.start = arm_oneshot_start,
|
||||||
|
.start_absolute = arm_oneshot_start_absolute,
|
||||||
|
.cancel = arm_oneshot_cancel,
|
||||||
|
.max_delay = arm_oneshot_max_delay,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct oneshot_lowerhalf_s g_arm_oneshot_lowerhalf =
|
||||||
|
{
|
||||||
|
.ops = &g_arm_oneshot_ops
|
||||||
|
};
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Public Functions
|
* Public Functions
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
struct oneshot_lowerhalf_s *arm_timer_initialize(unsigned int freq)
|
struct oneshot_lowerhalf_s *arm_timer_initialize(unsigned int freq)
|
||||||
{
|
{
|
||||||
struct arm_timer_lowerhalf_s *lower = &g_arm_timer_lowerhalf;
|
struct oneshot_lowerhalf_s *lower = &g_arm_oneshot_lowerhalf;
|
||||||
|
|
||||||
|
/* The init freq is for trust-zone only since CNTFRQ is only
|
||||||
|
* allowed to access in secure state.
|
||||||
|
*/
|
||||||
|
|
||||||
arm_timer_initialize_per_cpu(freq);
|
arm_timer_initialize_per_cpu(freq);
|
||||||
|
|
||||||
lower->freq = arm_timer_get_freq();
|
oneshot_count_init(lower, arm_timer_get_freq());
|
||||||
lower->lh.ops = &g_arm_timer_ops;
|
|
||||||
lower->running = -1;
|
|
||||||
|
|
||||||
irq_attach(GIC_IRQ_TIMER, arm_timer_interrupt, lower);
|
irq_attach(GIC_IRQ_TIMER, arm_timer_interrupt, lower);
|
||||||
|
|
||||||
return (struct oneshot_lowerhalf_s *)lower;
|
return lower;
|
||||||
}
|
}
|
||||||
|
|
||||||
void arm_timer_secondary_init(unsigned int freq)
|
void arm_timer_secondary_init(unsigned int freq)
|
||||||
|
|||||||
@@ -102,6 +102,7 @@ static struct arm_timer_lowerhalf_s g_arm_timer_lowerhalf;
|
|||||||
static inline void arm_timer_set_freq(uint32_t freq)
|
static inline void arm_timer_set_freq(uint32_t freq)
|
||||||
{
|
{
|
||||||
CP15_SET(CNTFRQ, freq);
|
CP15_SET(CNTFRQ, freq);
|
||||||
|
UP_ISB();
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint64_t arm_timer_phy_count(void)
|
static inline uint64_t arm_timer_phy_count(void)
|
||||||
@@ -123,12 +124,14 @@ static inline void arm_timer_phy_enable(bool enable)
|
|||||||
{
|
{
|
||||||
CP15_MODIFY((uint32_t)enable << CNT_CTL_ENABLE_BIT,
|
CP15_MODIFY((uint32_t)enable << CNT_CTL_ENABLE_BIT,
|
||||||
BIT(CNT_CTL_ENABLE_BIT), CNTP_CTL);
|
BIT(CNT_CTL_ENABLE_BIT), CNTP_CTL);
|
||||||
|
UP_ISB();
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void arm_timer_phy_set_irq_mask(bool mask)
|
static inline void arm_timer_phy_set_irq_mask(bool mask)
|
||||||
{
|
{
|
||||||
CP15_MODIFY((uint32_t)mask << CNT_CTL_IMASK_BIT,
|
CP15_MODIFY((uint32_t)mask << CNT_CTL_IMASK_BIT,
|
||||||
BIT(CNT_CTL_IMASK_BIT), CNTP_CTL);
|
BIT(CNT_CTL_IMASK_BIT), CNTP_CTL);
|
||||||
|
UP_ISB();
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint64_t nsec_from_count(uint64_t count, uint32_t freq)
|
static inline uint64_t nsec_from_count(uint64_t count, uint32_t freq)
|
||||||
|
|||||||
@@ -64,25 +64,6 @@
|
|||||||
#define ARM_ARCH_TIMER_PRIO IRQ_DEFAULT_PRIORITY
|
#define ARM_ARCH_TIMER_PRIO IRQ_DEFAULT_PRIORITY
|
||||||
#define ARM_ARCH_TIMER_FLAGS IRQ_TYPE_LEVEL
|
#define ARM_ARCH_TIMER_FLAGS IRQ_TYPE_LEVEL
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
* Private Types
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
struct arm_oneshot_lowerhalf_s
|
|
||||||
{
|
|
||||||
/* This is the part of the lower half driver that is visible to the upper-
|
|
||||||
* half client of the driver. This must be the first thing in this
|
|
||||||
* structure so that pointers to struct oneshot_lowerhalf_s are cast
|
|
||||||
* compatible to struct arm64_oneshot_lowerhalf_s and vice versa.
|
|
||||||
*/
|
|
||||||
|
|
||||||
struct oneshot_lowerhalf_s lh; /* Common lower-half driver fields */
|
|
||||||
|
|
||||||
/* Private lower half data follows */
|
|
||||||
|
|
||||||
uint32_t frequency; /* Frequency */
|
|
||||||
};
|
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Private Functions
|
* Private Functions
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
@@ -90,6 +71,7 @@ struct arm_oneshot_lowerhalf_s
|
|||||||
static inline void arm_timer_set_freq(uint32_t freq)
|
static inline void arm_timer_set_freq(uint32_t freq)
|
||||||
{
|
{
|
||||||
CP15_SET(CNTFRQ, freq);
|
CP15_SET(CNTFRQ, freq);
|
||||||
|
UP_ISB();
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint64_t arm_timer_phy_count(void)
|
static inline uint64_t arm_timer_phy_count(void)
|
||||||
@@ -111,16 +93,18 @@ static inline void arm_timer_phy_enable(bool enable)
|
|||||||
{
|
{
|
||||||
CP15_MODIFY((uint32_t)enable << CNT_CTL_ENABLE_BIT,
|
CP15_MODIFY((uint32_t)enable << CNT_CTL_ENABLE_BIT,
|
||||||
BIT(CNT_CTL_ENABLE_BIT), CNTP_CTL);
|
BIT(CNT_CTL_ENABLE_BIT), CNTP_CTL);
|
||||||
|
UP_ISB();
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void arm_timer_phy_set_irq_mask(bool mask)
|
static inline void arm_timer_phy_set_irq_mask(bool mask)
|
||||||
{
|
{
|
||||||
CP15_MODIFY((uint32_t)mask << CNT_CTL_IMASK_BIT,
|
CP15_MODIFY((uint32_t)mask << CNT_CTL_IMASK_BIT,
|
||||||
BIT(CNT_CTL_IMASK_BIT), CNTP_CTL);
|
BIT(CNT_CTL_IMASK_BIT), CNTP_CTL);
|
||||||
|
UP_ISB();
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Name: arm_arch_timer_compare_isr
|
* Name: arm_oneshot_compare_isr
|
||||||
*
|
*
|
||||||
* Description:
|
* Description:
|
||||||
* Common timer interrupt callback. When any oneshot timer interrupt
|
* Common timer interrupt callback. When any oneshot timer interrupt
|
||||||
@@ -135,187 +119,62 @@ static inline void arm_timer_phy_set_irq_mask(bool mask)
|
|||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
static int arm_arch_timer_compare_isr(int irq, void *regs, void *arg)
|
static int arm_oneshot_compare_isr(int irq, void *regs, void *arg)
|
||||||
{
|
{
|
||||||
struct arm_oneshot_lowerhalf_s *priv =
|
struct oneshot_lowerhalf_s *priv = (struct oneshot_lowerhalf_s *)arg;
|
||||||
(struct arm_oneshot_lowerhalf_s *)arg;
|
|
||||||
|
|
||||||
/* Suspend the timer irq, restart again when call tick_start */
|
arm_timer_phy_set_absolute(UINT64_MAX);
|
||||||
|
|
||||||
arm_timer_phy_set_irq_mask(true);
|
oneshot_process_callback(priv);
|
||||||
|
|
||||||
/* Then perform the callback */
|
|
||||||
|
|
||||||
oneshot_process_callback(&priv->lh);
|
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
static clkcnt_t arm_oneshot_max_delay(struct oneshot_lowerhalf_s *lower)
|
||||||
* Name: arm_max_delay
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
* Determine the maximum delay of the one-shot timer (in microseconds)
|
|
||||||
*
|
|
||||||
* Input Parameters:
|
|
||||||
* lower An instance of the lower-half oneshot state structure. This
|
|
||||||
* structure must have been previously initialized via a call to
|
|
||||||
* oneshot_initialize();
|
|
||||||
* ts The location in which to return the maximum delay.
|
|
||||||
*
|
|
||||||
* Returned Value:
|
|
||||||
* Zero (OK) is returned on success; a negated errno value is returned
|
|
||||||
* on failure.
|
|
||||||
*
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
static int arm_max_delay(struct oneshot_lowerhalf_s *lower,
|
|
||||||
struct timespec *ts)
|
|
||||||
{
|
{
|
||||||
struct arm_oneshot_lowerhalf_s *priv =
|
return UINT32_MAX;
|
||||||
(struct arm_oneshot_lowerhalf_s *)lower;
|
|
||||||
uint32_t freq = priv->frequency;
|
|
||||||
|
|
||||||
DEBUGASSERT(ts != NULL);
|
|
||||||
|
|
||||||
ts->tv_sec = UINT64_MAX / freq;
|
|
||||||
ts->tv_nsec = UINT64_MAX % freq * NSEC_PER_SEC / freq;
|
|
||||||
|
|
||||||
return OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
static clkcnt_t arm_oneshot_current(struct oneshot_lowerhalf_s *lower)
|
||||||
* Name: arm_cancel
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
* Cancel the oneshot timer and return the time remaining on the timer.
|
|
||||||
*
|
|
||||||
* NOTE: This function may execute at a high rate with no timer running (as
|
|
||||||
* when pre-emption is enabled and disabled).
|
|
||||||
*
|
|
||||||
* Input Parameters:
|
|
||||||
* lower Caller allocated instance of the oneshot state structure. This
|
|
||||||
* structure must have been previously initialized via a call to
|
|
||||||
* oneshot_initialize();
|
|
||||||
* ts The location in which to return the time remaining on the
|
|
||||||
* oneshot timer.
|
|
||||||
*
|
|
||||||
* Returned Value:
|
|
||||||
* Zero (OK) is returned on success. A call to up_timer_cancel() when
|
|
||||||
* the timer is not active should also return success; a negated errno
|
|
||||||
* value is returned on any failure.
|
|
||||||
*
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
static int arm_cancel(struct oneshot_lowerhalf_s *lower,
|
|
||||||
struct timespec *ts)
|
|
||||||
{
|
{
|
||||||
struct arm_oneshot_lowerhalf_s *priv =
|
/* We do not need memory barrier here. */
|
||||||
(struct arm_oneshot_lowerhalf_s *)lower;
|
|
||||||
|
|
||||||
DEBUGASSERT(priv != NULL && ts != NULL);
|
return arm_timer_phy_count();
|
||||||
|
|
||||||
/* Disable int */
|
|
||||||
|
|
||||||
arm_timer_phy_set_irq_mask(true);
|
|
||||||
|
|
||||||
return OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
static void arm_oneshot_start_absolute(struct oneshot_lowerhalf_s *lower,
|
||||||
* Name: arm_start
|
clkcnt_t expected)
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
* Start the oneshot timer
|
|
||||||
*
|
|
||||||
* Input Parameters:
|
|
||||||
* lower An instance of the lower-half oneshot state structure. This
|
|
||||||
* structure must have been previously initialized via a call to
|
|
||||||
* oneshot_initialize();
|
|
||||||
* handler The function to call when when the oneshot timer expires.
|
|
||||||
* arg An opaque argument that will accompany the callback.
|
|
||||||
* ts Provides the duration of the one shot timer.
|
|
||||||
*
|
|
||||||
* Returned Value:
|
|
||||||
* Zero (OK) is returned on success; a negated errno value is returned
|
|
||||||
* on failure.
|
|
||||||
*
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
static int arm_start(struct oneshot_lowerhalf_s *lower,
|
|
||||||
const struct timespec *ts)
|
|
||||||
{
|
{
|
||||||
uint64_t count;
|
arm_timer_phy_set_absolute(expected);
|
||||||
struct arm_oneshot_lowerhalf_s *priv =
|
|
||||||
(struct arm_oneshot_lowerhalf_s *)lower;
|
|
||||||
uint64_t freq = priv->frequency;
|
|
||||||
|
|
||||||
DEBUGASSERT(priv && ts);
|
|
||||||
|
|
||||||
/* Set the timeout */
|
|
||||||
|
|
||||||
count = arm_timer_phy_count();
|
|
||||||
count += (uint64_t)ts->tv_sec * freq +
|
|
||||||
(uint64_t)ts->tv_nsec * freq / NSEC_PER_SEC;
|
|
||||||
|
|
||||||
arm_timer_phy_set_absolute(count);
|
|
||||||
|
|
||||||
/* Try to unmask the timer irq in timer controller
|
|
||||||
* in case of arm_tick_cancel is called.
|
|
||||||
*/
|
|
||||||
|
|
||||||
arm_timer_phy_set_irq_mask(false);
|
|
||||||
|
|
||||||
return OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
static void arm_oneshot_start(struct oneshot_lowerhalf_s *lower,
|
||||||
* Name: arm_current
|
clkcnt_t delta)
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
* Get the current time.
|
|
||||||
*
|
|
||||||
* Input Parameters:
|
|
||||||
* lower Caller allocated instance of the oneshot state structure. This
|
|
||||||
* structure must have been previously initialized via a call to
|
|
||||||
* oneshot_initialize();
|
|
||||||
* ts The location in which to return the current time.
|
|
||||||
*
|
|
||||||
* Returned Value:
|
|
||||||
* Zero (OK) is returned on success, a negated errno value is returned on
|
|
||||||
* any failure.
|
|
||||||
*
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
static int arm_current(struct oneshot_lowerhalf_s *lower,
|
|
||||||
struct timespec *ts)
|
|
||||||
{
|
{
|
||||||
uint64_t count;
|
arm_timer_phy_set_relative(delta);
|
||||||
uint32_t freq;
|
}
|
||||||
struct arm_oneshot_lowerhalf_s *priv =
|
|
||||||
(struct arm_oneshot_lowerhalf_s *)lower;
|
|
||||||
|
|
||||||
DEBUGASSERT(ts != NULL);
|
static void arm_oneshot_cancel(struct oneshot_lowerhalf_s *lower)
|
||||||
|
{
|
||||||
freq = priv->frequency;
|
arm_timer_phy_set_absolute(UINT64_MAX);
|
||||||
count = arm_timer_phy_count();
|
|
||||||
|
|
||||||
ts->tv_sec = count / freq;
|
|
||||||
ts->tv_nsec = (count % freq) * NSEC_PER_SEC / freq;
|
|
||||||
|
|
||||||
return OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Private Data
|
* Private Data
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
static const struct oneshot_operations_s g_oneshot_ops =
|
static const struct oneshot_operations_s g_arm_oneshot_ops =
|
||||||
{
|
{
|
||||||
.start = arm_start,
|
.current = arm_oneshot_current,
|
||||||
.current = arm_current,
|
.start = arm_oneshot_start,
|
||||||
.max_delay = arm_max_delay,
|
.start_absolute = arm_oneshot_start_absolute,
|
||||||
.cancel = arm_cancel,
|
.cancel = arm_oneshot_cancel,
|
||||||
|
.max_delay = arm_oneshot_max_delay
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct oneshot_lowerhalf_s g_arm_oneshot_lowerhalf =
|
||||||
|
{
|
||||||
|
.ops = &g_arm_oneshot_ops
|
||||||
};
|
};
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
@@ -333,41 +192,24 @@ static const struct oneshot_operations_s g_oneshot_ops =
|
|||||||
|
|
||||||
static struct oneshot_lowerhalf_s *arm_oneshot_initialize(void)
|
static struct oneshot_lowerhalf_s *arm_oneshot_initialize(void)
|
||||||
{
|
{
|
||||||
struct arm_oneshot_lowerhalf_s *priv;
|
struct oneshot_lowerhalf_s *priv = &g_arm_oneshot_lowerhalf;
|
||||||
|
uint64_t freq;
|
||||||
|
|
||||||
tmrinfo("oneshot_initialize\n");
|
tmrinfo("oneshot_initialize\n");
|
||||||
|
|
||||||
/* Allocate an instance of the lower half driver */
|
|
||||||
|
|
||||||
priv = (struct arm_oneshot_lowerhalf_s *)
|
|
||||||
kmm_zalloc(sizeof(struct arm_oneshot_lowerhalf_s));
|
|
||||||
|
|
||||||
if (priv == NULL)
|
|
||||||
{
|
|
||||||
tmrerr("ERROR: Failed to initialized state structure\n");
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Initialize the lower-half driver structure */
|
|
||||||
|
|
||||||
DEBUGASSERT(arm_timer_get_freq() <= UINT32_MAX);
|
|
||||||
|
|
||||||
priv->lh.ops = &g_oneshot_ops;
|
|
||||||
priv->frequency = arm_timer_get_freq();
|
|
||||||
|
|
||||||
/* Attach handler */
|
/* Attach handler */
|
||||||
|
|
||||||
irq_attach(ARM_ARCH_TIMER_IRQ,
|
irq_attach(ARM_ARCH_TIMER_IRQ, arm_oneshot_compare_isr, priv);
|
||||||
arm_arch_timer_compare_isr, priv);
|
|
||||||
|
|
||||||
/* Avoid early timer irq cause abort. */
|
freq = arm_timer_get_freq();
|
||||||
|
|
||||||
arm_timer_phy_set_irq_mask(true);
|
DEBUGASSERT(freq <= UINT32_MAX);
|
||||||
|
|
||||||
tmrinfo("oneshot_initialize ok %p \n", &priv->lh);
|
oneshot_count_init(priv, (uint32_t)freq);
|
||||||
|
|
||||||
return &priv->lh;
|
tmrinfo("oneshot_initialize ok %p \n", priv);
|
||||||
|
|
||||||
|
return priv;
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
@@ -392,8 +234,12 @@ void up_timer_initialize(void)
|
|||||||
__func__, freq / 1000000, (freq / 10000) % 100);
|
__func__, freq / 1000000, (freq / 10000) % 100);
|
||||||
|
|
||||||
up_alarm_set_lowerhalf(arm_oneshot_initialize());
|
up_alarm_set_lowerhalf(arm_oneshot_initialize());
|
||||||
|
|
||||||
|
arm_timer_phy_set_absolute(UINT64_MAX);
|
||||||
|
|
||||||
up_enable_irq(ARM_ARCH_TIMER_IRQ);
|
up_enable_irq(ARM_ARCH_TIMER_IRQ);
|
||||||
arm_timer_phy_enable(true);
|
arm_timer_phy_enable(true);
|
||||||
|
arm_timer_phy_set_irq_mask(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_SMP
|
#ifdef CONFIG_SMP
|
||||||
@@ -422,6 +268,8 @@ void arm_timer_secondary_init(unsigned int freq)
|
|||||||
#ifdef CONFIG_SCHED_TICKLESS
|
#ifdef CONFIG_SCHED_TICKLESS
|
||||||
tmrinfo("arm_arch_timer_secondary_init\n");
|
tmrinfo("arm_arch_timer_secondary_init\n");
|
||||||
|
|
||||||
|
arm_timer_phy_set_absolute(UINT64_MAX);
|
||||||
|
|
||||||
/* Enable int */
|
/* Enable int */
|
||||||
|
|
||||||
up_enable_irq(ARM_ARCH_TIMER_IRQ);
|
up_enable_irq(ARM_ARCH_TIMER_IRQ);
|
||||||
@@ -429,6 +277,7 @@ void arm_timer_secondary_init(unsigned int freq)
|
|||||||
/* Start timer */
|
/* Start timer */
|
||||||
|
|
||||||
arm_timer_phy_enable(true);
|
arm_timer_phy_enable(true);
|
||||||
|
arm_timer_phy_set_irq_mask(false);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user