arch/tricore: Add the clkdev driver for tricore.
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:
ouyangxiangzhen
2025-09-26 11:12:35 +08:00
committed by Xiang Xiao
parent 3b52763385
commit ff5944d8fc
4 changed files with 106 additions and 110 deletions
+1
View File
@@ -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.
+103 -104
View File
@@ -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,
-6
View File
@@ -34,12 +34,6 @@
#include "IfxStm.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define SCU_FREQUENCY 100000000UL
/****************************************************************************
* Public Functions
****************************************************************************/