mirror of
https://github.com/apache/nuttx.git
synced 2026-05-30 21:36:28 +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 ARCH_TC3XX
|
||||||
select ALARM_ARCH
|
select ALARM_ARCH
|
||||||
select ONESHOT
|
select ONESHOT
|
||||||
|
select ONESHOT_COUNT
|
||||||
---help---
|
---help---
|
||||||
AURIX TC39x family: TC397
|
AURIX TC39x family: TC397
|
||||||
|
|
||||||
|
|||||||
@@ -46,6 +46,8 @@
|
|||||||
* Pre-processor Definitions
|
* Pre-processor Definitions
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
|
#define SCU_FREQUENCY 100000000UL
|
||||||
|
|
||||||
/* Determine which (if any) console driver to use. If a console is enabled
|
/* 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
|
* and no other console device is specified, then a serial console is
|
||||||
* assumed.
|
* assumed.
|
||||||
|
|||||||
@@ -34,6 +34,24 @@
|
|||||||
|
|
||||||
#include "IfxStm.h"
|
#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
|
* Private Types
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
@@ -46,40 +64,7 @@
|
|||||||
struct tricore_systimer_lowerhalf_s
|
struct tricore_systimer_lowerhalf_s
|
||||||
{
|
{
|
||||||
struct oneshot_lowerhalf_s lower;
|
struct oneshot_lowerhalf_s lower;
|
||||||
volatile void *tbase;
|
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,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
@@ -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
|
* lower An instance of the lower-half oneshot state structure. This
|
||||||
* structure must have been previously initialized via a call to
|
* structure must have been previously initialized via a call to
|
||||||
* oneshot_initialize();
|
* oneshot_initialize();
|
||||||
* ts The location in which to return the maximum delay.
|
|
||||||
*
|
*
|
||||||
* Returned Value:
|
* Returned Value:
|
||||||
* Zero (OK) is returned on success; a negated errno value is returned
|
* The maximum delay value.
|
||||||
* on failure.
|
|
||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
static int tricore_systimer_max_delay(struct oneshot_lowerhalf_s *lower,
|
static clkcnt_t tricore_systimer_max_delay(struct oneshot_lowerhalf_s *lower)
|
||||||
struct timespec *ts)
|
|
||||||
{
|
{
|
||||||
ts->tv_sec = UINT32_MAX;
|
return UINT32_MAX;
|
||||||
ts->tv_nsec = NSEC_PER_SEC - 1;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Name: tricore_systimer_start
|
* Name: tricore_systimer_start
|
||||||
*
|
*
|
||||||
* Description:
|
* 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:
|
* Input Parameters:
|
||||||
* lower An instance of the lower-half oneshot state structure. This
|
* lower An instance of the lower-half oneshot state structure. This
|
||||||
* structure must have been previously initialized via a call to
|
* structure must have been previously initialized via a call to
|
||||||
* oneshot_initialize();
|
* oneshot_initialize();
|
||||||
* handler The function to call when when the oneshot timer expires.
|
* delta Provides the duration of delta count.
|
||||||
* arg An opaque argument that will accompany the callback.
|
|
||||||
* ts Provides the duration of the one shot timer.
|
|
||||||
*
|
*
|
||||||
* Returned Value:
|
* Returned Value:
|
||||||
* Zero (OK) is returned on success; a negated errno value is returned
|
* None.
|
||||||
* on failure.
|
|
||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
static int tricore_systimer_start(struct oneshot_lowerhalf_s *lower,
|
static void tricore_systimer_start(struct oneshot_lowerhalf_s *lower,
|
||||||
const struct timespec *ts)
|
clkcnt_t delta)
|
||||||
{
|
{
|
||||||
struct tricore_systimer_lowerhalf_s *priv =
|
struct tricore_systimer_lowerhalf_s *priv =
|
||||||
(struct tricore_systimer_lowerhalf_s *)lower;
|
(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 +
|
delta = delta < TRICORE_SYSTIMER_MIN_DELAY ?
|
||||||
ts->tv_nsec * priv->freq / NSEC_PER_SEC;
|
TRICORE_SYSTIMER_MIN_DELAY : delta;
|
||||||
if (priv->alarm < mtime)
|
flags = up_irq_save();
|
||||||
{
|
mtime = tricore_systimer_get_time(priv);
|
||||||
priv->alarm = UINT64_MAX;
|
|
||||||
}
|
|
||||||
|
|
||||||
tricore_systimer_set_timecmp(priv, priv->alarm);
|
tricore_systimer_set_timecmp(priv, mtime + delta);
|
||||||
return 0;
|
|
||||||
|
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
|
* lower Caller allocated instance of the oneshot state structure. This
|
||||||
* structure must have been previously initialized via a call to
|
* structure must have been previously initialized via a call to
|
||||||
* oneshot_initialize();
|
* 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:
|
* Returned Value:
|
||||||
* Zero (OK) is returned on success. A call to up_timer_cancel() when
|
* None.
|
||||||
* the timer is not active should also return success; a negated errno
|
|
||||||
* value is returned on any failure.
|
|
||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
static int tricore_systimer_cancel(struct oneshot_lowerhalf_s *lower,
|
static void tricore_systimer_cancel(struct oneshot_lowerhalf_s *lower)
|
||||||
struct timespec *ts)
|
|
||||||
{
|
{
|
||||||
struct tricore_systimer_lowerhalf_s *priv =
|
struct tricore_systimer_lowerhalf_s *priv =
|
||||||
(struct tricore_systimer_lowerhalf_s *)lower;
|
(struct tricore_systimer_lowerhalf_s *)lower;
|
||||||
uint64_t mtime;
|
|
||||||
|
|
||||||
tricore_systimer_set_timecmp(priv, UINT64_MAX);
|
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
|
* lower Caller allocated instance of the oneshot state structure. This
|
||||||
* structure must have been previously initialized via a call to
|
* structure must have been previously initialized via a call to
|
||||||
* oneshot_initialize();
|
* oneshot_initialize();
|
||||||
* ts The location in which to return the current time. A time of zero
|
|
||||||
* is returned for the initialization moment.
|
|
||||||
*
|
*
|
||||||
* Returned Value:
|
* Returned Value:
|
||||||
* Zero (OK) is returned on success, a negated errno value is returned on
|
* Current timer count.
|
||||||
* any failure.
|
|
||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
static int tricore_systimer_current(struct oneshot_lowerhalf_s *lower,
|
static clkcnt_t tricore_systimer_current(struct oneshot_lowerhalf_s *lower)
|
||||||
struct timespec *ts)
|
|
||||||
{
|
{
|
||||||
struct tricore_systimer_lowerhalf_s *priv =
|
struct tricore_systimer_lowerhalf_s *priv =
|
||||||
(struct tricore_systimer_lowerhalf_s *)lower;
|
(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;
|
return tricore_systimer_get_time(priv);
|
||||||
ts->tv_nsec = nsec % NSEC_PER_SEC;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
@@ -278,12 +256,31 @@ static int tricore_systimer_interrupt(int irq, void *context, void *arg)
|
|||||||
{
|
{
|
||||||
struct tricore_systimer_lowerhalf_s *priv = 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);
|
oneshot_process_callback(&priv->lower);
|
||||||
|
|
||||||
return 0;
|
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
|
* Public Functions
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
@@ -300,11 +297,13 @@ static int tricore_systimer_interrupt(int irq, void *context, void *arg)
|
|||||||
struct oneshot_lowerhalf_s *
|
struct oneshot_lowerhalf_s *
|
||||||
tricore_systimer_initialize(volatile void *tbase, int irq, uint64_t freq)
|
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->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_setCompareControl(tbase,
|
||||||
IfxStm_Comparator_0,
|
IfxStm_Comparator_0,
|
||||||
|
|||||||
@@ -34,12 +34,6 @@
|
|||||||
|
|
||||||
#include "IfxStm.h"
|
#include "IfxStm.h"
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
* Pre-processor Definitions
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#define SCU_FREQUENCY 100000000UL
|
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* Public Functions
|
* Public Functions
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|||||||
Reference in New Issue
Block a user