mirror of
https://github.com/apache/nuttx.git
synced 2026-05-21 04:52:02 +08:00
arch/tricore: Add the clkdev driver for tricore.
Build Documentation / build-html (push) Has been cancelled
Build Documentation / build-html (push) Has been cancelled
This commit added the clkdev driver for tricore. Signed-off-by: ouyangxiangzhen <ouyangxiangzhen@xiaomi.com>
This commit is contained in:
committed by
Xiang Xiao
parent
3b52763385
commit
ff5944d8fc
@@ -41,6 +41,7 @@ config ARCH_CHIP_TC397
|
||||
select ARCH_TC3XX
|
||||
select ALARM_ARCH
|
||||
select ONESHOT
|
||||
select ONESHOT_COUNT
|
||||
---help---
|
||||
AURIX TC39x family: TC397
|
||||
|
||||
|
||||
@@ -46,6 +46,8 @@
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
#define SCU_FREQUENCY 100000000UL
|
||||
|
||||
/* Determine which (if any) console driver to use. If a console is enabled
|
||||
* and no other console device is specified, then a serial console is
|
||||
* assumed.
|
||||
|
||||
@@ -34,6 +34,24 @@
|
||||
|
||||
#include "IfxStm.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/* Since the tricore hardware timer triggers an interrupt only when the
|
||||
* compare value is equal to the counter, setting a compare value that has
|
||||
* already timed out will not trigger an interrupt. To avoid missing
|
||||
* interrupts when setting the timer, we should set a minimum delay.
|
||||
* The minimum delay is calculated based on the CPU frequency and the timer
|
||||
* frequency. We assume that the worst-case execution time for setting the
|
||||
* timer does not exceed 40 CPU cycles, and calculate the minimum timer
|
||||
* delay accordingly.
|
||||
* 40 CPU cycles (100ns at 400Mhz) ~ 10 timer cycles (for 100 Mhz timer).
|
||||
*/
|
||||
|
||||
#define TRICORE_SYSTIMER_MIN_DELAY \
|
||||
(40ull * SCU_FREQUENCY / IFX_CFG_CPU_CLOCK_FREQUENCY)
|
||||
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
@@ -46,40 +64,7 @@
|
||||
struct tricore_systimer_lowerhalf_s
|
||||
{
|
||||
struct oneshot_lowerhalf_s lower;
|
||||
volatile void *tbase;
|
||||
uint64_t freq;
|
||||
uint64_t alarm;
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
static int tricore_systimer_max_delay(struct oneshot_lowerhalf_s *lower,
|
||||
struct timespec *ts);
|
||||
static int tricore_systimer_start(struct oneshot_lowerhalf_s *lower,
|
||||
const struct timespec *ts);
|
||||
static int tricore_systimer_cancel(struct oneshot_lowerhalf_s *lower,
|
||||
struct timespec *ts);
|
||||
static int tricore_systimer_current(struct oneshot_lowerhalf_s *lower,
|
||||
struct timespec *ts);
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
static const struct oneshot_operations_s g_tricore_systimer_ops =
|
||||
{
|
||||
.max_delay = tricore_systimer_max_delay,
|
||||
.start = tricore_systimer_start,
|
||||
.cancel = tricore_systimer_cancel,
|
||||
.current = tricore_systimer_current,
|
||||
};
|
||||
|
||||
static struct tricore_systimer_lowerhalf_s g_systimer_lower =
|
||||
{
|
||||
.lower.ops = &g_tricore_systimer_ops,
|
||||
volatile void *tbase;
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
@@ -124,59 +109,87 @@ tricore_systimer_set_timecmp(struct tricore_systimer_lowerhalf_s *priv,
|
||||
* 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.
|
||||
* The maximum delay value.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int tricore_systimer_max_delay(struct oneshot_lowerhalf_s *lower,
|
||||
struct timespec *ts)
|
||||
static clkcnt_t tricore_systimer_max_delay(struct oneshot_lowerhalf_s *lower)
|
||||
{
|
||||
ts->tv_sec = UINT32_MAX;
|
||||
ts->tv_nsec = NSEC_PER_SEC - 1;
|
||||
|
||||
return 0;
|
||||
return UINT32_MAX;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: tricore_systimer_start
|
||||
*
|
||||
* Description:
|
||||
* Start the oneshot timer
|
||||
* Start the oneshot timer. Note that the tricore systimer is special, the
|
||||
* IRQ is only triggered when timecmp == mtime, so we should avoid the case
|
||||
* that we miss the timecmp.
|
||||
*
|
||||
* 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.
|
||||
* delta Provides the duration of delta count.
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero (OK) is returned on success; a negated errno value is returned
|
||||
* on failure.
|
||||
* None.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int tricore_systimer_start(struct oneshot_lowerhalf_s *lower,
|
||||
const struct timespec *ts)
|
||||
static void tricore_systimer_start(struct oneshot_lowerhalf_s *lower,
|
||||
clkcnt_t delta)
|
||||
{
|
||||
struct tricore_systimer_lowerhalf_s *priv =
|
||||
(struct tricore_systimer_lowerhalf_s *)lower;
|
||||
uint64_t mtime = tricore_systimer_get_time(priv);
|
||||
irqstate_t flags;
|
||||
uint64_t mtime;
|
||||
|
||||
priv->alarm = mtime + ts->tv_sec * priv->freq +
|
||||
ts->tv_nsec * priv->freq / NSEC_PER_SEC;
|
||||
if (priv->alarm < mtime)
|
||||
{
|
||||
priv->alarm = UINT64_MAX;
|
||||
}
|
||||
delta = delta < TRICORE_SYSTIMER_MIN_DELAY ?
|
||||
TRICORE_SYSTIMER_MIN_DELAY : delta;
|
||||
flags = up_irq_save();
|
||||
mtime = tricore_systimer_get_time(priv);
|
||||
|
||||
tricore_systimer_set_timecmp(priv, priv->alarm);
|
||||
return 0;
|
||||
tricore_systimer_set_timecmp(priv, mtime + delta);
|
||||
|
||||
up_irq_restore(flags);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: tricore_systimer_start_absolute
|
||||
*
|
||||
* Description:
|
||||
* Start the oneshot timer. Note that the tricore systimer is special, the
|
||||
* IRQ is only triggered when timecmp == mtime, so we should avoid the case
|
||||
* that we miss the timecmp.
|
||||
*
|
||||
* 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();
|
||||
* expected Target
|
||||
*
|
||||
* Returned Value:
|
||||
* None.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void
|
||||
tricore_systimer_start_absolute(struct oneshot_lowerhalf_s *lower,
|
||||
clkcnt_t expected)
|
||||
{
|
||||
struct tricore_systimer_lowerhalf_s *priv =
|
||||
(struct tricore_systimer_lowerhalf_s *)lower;
|
||||
|
||||
irqstate_t flags = up_irq_save();
|
||||
uint64_t min_expected = tricore_systimer_get_time(priv) +
|
||||
TRICORE_SYSTIMER_MIN_DELAY;
|
||||
expected = expected < min_expected ? min_expected : expected;
|
||||
tricore_systimer_set_timecmp(priv, expected);
|
||||
|
||||
up_irq_restore(flags);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@@ -192,44 +205,18 @@ static int tricore_systimer_start(struct oneshot_lowerhalf_s *lower,
|
||||
* 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. A time of zero is returned if the timer is
|
||||
* not running.
|
||||
*
|
||||
* 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.
|
||||
* None.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int tricore_systimer_cancel(struct oneshot_lowerhalf_s *lower,
|
||||
struct timespec *ts)
|
||||
static void tricore_systimer_cancel(struct oneshot_lowerhalf_s *lower)
|
||||
{
|
||||
struct tricore_systimer_lowerhalf_s *priv =
|
||||
(struct tricore_systimer_lowerhalf_s *)lower;
|
||||
uint64_t mtime;
|
||||
|
||||
tricore_systimer_set_timecmp(priv, UINT64_MAX);
|
||||
|
||||
mtime = tricore_systimer_get_time(priv);
|
||||
if (priv->alarm > mtime)
|
||||
{
|
||||
uint64_t nsec = (priv->alarm - mtime) *
|
||||
NSEC_PER_SEC / priv->freq;
|
||||
|
||||
ts->tv_sec = nsec / NSEC_PER_SEC;
|
||||
ts->tv_nsec = nsec % NSEC_PER_SEC;
|
||||
}
|
||||
else
|
||||
{
|
||||
ts->tv_sec = 0;
|
||||
ts->tv_nsec = 0;
|
||||
}
|
||||
|
||||
priv->alarm = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@@ -242,27 +229,18 @@ static int tricore_systimer_cancel(struct oneshot_lowerhalf_s *lower,
|
||||
* 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. A time of zero
|
||||
* is returned for the initialization moment.
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero (OK) is returned on success, a negated errno value is returned on
|
||||
* any failure.
|
||||
* Current timer count.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int tricore_systimer_current(struct oneshot_lowerhalf_s *lower,
|
||||
struct timespec *ts)
|
||||
static clkcnt_t tricore_systimer_current(struct oneshot_lowerhalf_s *lower)
|
||||
{
|
||||
struct tricore_systimer_lowerhalf_s *priv =
|
||||
(struct tricore_systimer_lowerhalf_s *)lower;
|
||||
uint64_t mtime = tricore_systimer_get_time(priv);
|
||||
uint64_t nsec = mtime / (priv->freq / USEC_PER_SEC) * NSEC_PER_USEC;
|
||||
|
||||
ts->tv_sec = nsec / NSEC_PER_SEC;
|
||||
ts->tv_nsec = nsec % NSEC_PER_SEC;
|
||||
|
||||
return 0;
|
||||
return tricore_systimer_get_time(priv);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@@ -278,12 +256,31 @@ static int tricore_systimer_interrupt(int irq, void *context, void *arg)
|
||||
{
|
||||
struct tricore_systimer_lowerhalf_s *priv = arg;
|
||||
|
||||
tricore_systimer_set_timecmp(priv, UINT64_MAX);
|
||||
/* We do not need to clear the compare register here. */
|
||||
|
||||
oneshot_process_callback(&priv->lower);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
static const struct oneshot_operations_s g_tricore_oneshot_ops =
|
||||
{
|
||||
.current = tricore_systimer_current,
|
||||
.start = tricore_systimer_start,
|
||||
.start_absolute = tricore_systimer_start_absolute,
|
||||
.cancel = tricore_systimer_cancel,
|
||||
.max_delay = tricore_systimer_max_delay
|
||||
};
|
||||
|
||||
static struct tricore_systimer_lowerhalf_s g_tricore_oneshot_lowerhalf =
|
||||
{
|
||||
.lower.ops = &g_tricore_oneshot_ops
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
@@ -300,11 +297,13 @@ static int tricore_systimer_interrupt(int irq, void *context, void *arg)
|
||||
struct oneshot_lowerhalf_s *
|
||||
tricore_systimer_initialize(volatile void *tbase, int irq, uint64_t freq)
|
||||
{
|
||||
struct tricore_systimer_lowerhalf_s *priv = &g_systimer_lower;
|
||||
struct tricore_systimer_lowerhalf_s *priv = &g_tricore_oneshot_lowerhalf;
|
||||
|
||||
priv->tbase = tbase;
|
||||
priv->freq = freq;
|
||||
spin_lock_init(&priv->lock);
|
||||
|
||||
ASSERT(freq <= UINT32_MAX);
|
||||
|
||||
oneshot_count_init(&priv->lower, (uint32_t)freq);
|
||||
|
||||
IfxStm_setCompareControl(tbase,
|
||||
IfxStm_Comparator_0,
|
||||
|
||||
@@ -34,12 +34,6 @@
|
||||
|
||||
#include "IfxStm.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
#define SCU_FREQUENCY 100000000UL
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
Reference in New Issue
Block a user