driver/timers: Simplify Goldfish timer driver.

This commit simplified goldfish timer driver for better performance.

Signed-off-by: ouyangxiangzhen <ouyangxiangzhen@xiaomi.com>
This commit is contained in:
ouyangxiangzhen 2025-11-03 15:59:07 +08:00 committed by Xiang Xiao
parent 5296b8d3e3
commit 6f17f1ce81

View file

@ -27,7 +27,6 @@
#include <nuttx/config.h>
#include <nuttx/arch.h>
#include <nuttx/irq.h>
#include <nuttx/kmalloc.h>
#include <nuttx/timers/oneshot.h>
#include <nuttx/spinlock.h>
@ -65,129 +64,21 @@ struct goldfish_timer_lowerhalf_s
{
struct oneshot_lowerhalf_s lh; /* Lower half operations */
uintptr_t base; /* Base address of registers */
spinlock_t lock; /* Lock for interrupt handling */
spinlock_t lock; /* Lock for setting timer */
spinlock_t read_lock; /* Lock for reading time */
};
/****************************************************************************
* Inline Functions
* Private Function Prototypes
****************************************************************************/
static inline_function uint64_t goldfish_timer_get_nsec(uintptr_t base)
{
uint32_t l32;
uint32_t h32;
l32 = getreg32(base + GOLDFISH_TIMER_TIME_LOW);
h32 = getreg32(base + GOLDFISH_TIMER_TIME_HIGH);
return ((uint64_t)h32 << 32) | l32;
}
static inline_function
void goldfish_timer_set_nsec(uintptr_t base, uint64_t expected)
{
putreg32(1, base + GOLDFISH_TIMER_CLEAR_ALARM);
putreg32(expected >> 32, base + GOLDFISH_TIMER_ALARM_HIGH);
putreg32(expected, base + GOLDFISH_TIMER_ALARM_LOW);
}
/****************************************************************************
* Private Functions
****************************************************************************/
static int goldfish_timer_interrupt(int irq,
FAR void *context,
FAR void *arg)
{
FAR struct goldfish_timer_lowerhalf_s *lower = arg;
irqstate_t flags;
DEBUGASSERT(lower != NULL);
flags = spin_lock_irqsave(&lower->lock);
putreg32(1, lower->base + GOLDFISH_TIMER_CLEAR_INTERRUPT);
spin_unlock_irqrestore(&lower->lock, flags);
/* Then perform the callback */
oneshot_process_callback(&lower->lh);
return 0;
}
static clkcnt_t goldfish_timer_max_delay(struct oneshot_lowerhalf_s *lower)
{
return UINT64_MAX;
}
static clkcnt_t goldfish_timer_current(struct oneshot_lowerhalf_s *lower_)
{
FAR struct goldfish_timer_lowerhalf_s *lower =
(FAR struct goldfish_timer_lowerhalf_s *)lower_;
irqstate_t flags;
uint64_t nsec;
DEBUGASSERT(lower != NULL);
flags = spin_lock_irqsave(&lower->lock);
nsec = goldfish_timer_get_nsec(lower->base);
spin_unlock_irqrestore(&lower->lock, flags);
return nsec;
}
static clkcnt_t goldfish_timer_max_delay(struct oneshot_lowerhalf_s *lower);
static clkcnt_t goldfish_timer_current(struct oneshot_lowerhalf_s *lower_);
static void goldfish_timer_start_absolute(struct oneshot_lowerhalf_s *lower_,
clkcnt_t expected)
{
FAR struct goldfish_timer_lowerhalf_s *lower =
(FAR struct goldfish_timer_lowerhalf_s *)lower_;
irqstate_t flags;
DEBUGASSERT(lower != NULL);
flags = spin_lock_irqsave(&lower->lock);
goldfish_timer_set_nsec(lower->base, expected);
spin_unlock_irqrestore(&lower->lock, flags);
}
clkcnt_t expected);
static void goldfish_timer_start(struct oneshot_lowerhalf_s *lower_,
clkcnt_t delta)
{
FAR struct goldfish_timer_lowerhalf_s *lower =
(FAR struct goldfish_timer_lowerhalf_s *)lower_;
irqstate_t flags;
DEBUGASSERT(lower != NULL);
flags = spin_lock_irqsave(&lower->lock);
delta += goldfish_timer_get_nsec(lower->base);
goldfish_timer_set_nsec(lower->base, delta);
spin_unlock_irqrestore(&lower->lock, flags);
}
static void goldfish_timer_cancel(struct oneshot_lowerhalf_s *lower_)
{
struct goldfish_timer_lowerhalf_s *lower =
(struct goldfish_timer_lowerhalf_s *)lower_;
irqstate_t flags;
DEBUGASSERT(lower != NULL);
flags = spin_lock_irqsave(&lower->lock);
goldfish_timer_set_nsec(lower->base, UINT64_MAX);
spin_unlock_irqrestore(&lower->lock, flags);
}
clkcnt_t delta);
static void goldfish_timer_cancel(struct oneshot_lowerhalf_s *lower_);
/****************************************************************************
* Private Data
@ -207,6 +98,99 @@ static struct goldfish_timer_lowerhalf_s g_goldfish_timer_lowerhalf =
.lh.ops = &g_goldfish_timer_ops
};
/****************************************************************************
* Inline Functions
****************************************************************************/
static inline_function uint64_t goldfish_timer_get_nsec(uintptr_t base)
{
uint32_t l32 = getreg32(base + GOLDFISH_TIMER_TIME_LOW);
uint32_t h32 = getreg32(base + GOLDFISH_TIMER_TIME_HIGH);
return ((uint64_t)h32 << 32) | l32;
}
static inline_function
void goldfish_timer_set_nsec(uintptr_t base, uint64_t expected)
{
putreg32(expected >> 32, base + GOLDFISH_TIMER_ALARM_HIGH);
putreg32(expected, base + GOLDFISH_TIMER_ALARM_LOW);
}
/****************************************************************************
* Private Functions
****************************************************************************/
static int goldfish_timer_interrupt(int irq, FAR void *context,
FAR void *arg)
{
FAR struct goldfish_timer_lowerhalf_s *lower = &g_goldfish_timer_lowerhalf;
/* Only one core can handle the IRQ, so lock is not required. */
putreg32(1, lower->base + GOLDFISH_TIMER_CLEAR_INTERRUPT);
/* Then perform the callback */
oneshot_process_callback(&lower->lh);
return 0;
}
static clkcnt_t goldfish_timer_max_delay(struct oneshot_lowerhalf_s *lower)
{
return UINT64_MAX;
}
static clkcnt_t goldfish_timer_current(struct oneshot_lowerhalf_s *lower_)
{
/* Do not remove the read lock here, because the access to the
* GOLDFISH_TIMER_TIME_LOW will update the whole GOLDFISH_TIMER_TIME.
*/
FAR struct goldfish_timer_lowerhalf_s *lower = &g_goldfish_timer_lowerhalf;
irqstate_t flags = spin_lock_irqsave(&lower->read_lock);
uint64_t nsec = goldfish_timer_get_nsec(lower->base);
spin_unlock_irqrestore(&lower->read_lock, flags);
return nsec;
}
static void goldfish_timer_start_absolute(struct oneshot_lowerhalf_s *lower_,
clkcnt_t expected)
{
FAR struct goldfish_timer_lowerhalf_s *lower = &g_goldfish_timer_lowerhalf;
irqstate_t flags = spin_lock_irqsave(&lower->lock);
goldfish_timer_set_nsec(lower->base, expected);
spin_unlock_irqrestore(&lower->lock, flags);
}
static void goldfish_timer_start(struct oneshot_lowerhalf_s *lower_,
clkcnt_t delta)
{
FAR struct goldfish_timer_lowerhalf_s *lower = &g_goldfish_timer_lowerhalf;
irqstate_t flags = spin_lock_irqsave(&lower->lock);
delta += goldfish_timer_get_nsec(lower->base);
goldfish_timer_set_nsec(lower->base, delta);
spin_unlock_irqrestore(&lower->lock, flags);
}
static void goldfish_timer_cancel(struct oneshot_lowerhalf_s *lower_)
{
FAR struct goldfish_timer_lowerhalf_s *lower = &g_goldfish_timer_lowerhalf;
irqstate_t flags = spin_lock_irqsave(&lower->lock);
/* Disable the timer and clear the interrupt. */
putreg32(1, lower->base + GOLDFISH_TIMER_CLEAR_ALARM);
spin_unlock_irqrestore(&lower->lock, flags);
}
/****************************************************************************
* Public Functions
****************************************************************************/
@ -219,13 +203,14 @@ goldfish_timer_initialize(uintptr_t base, int irq)
lower->base = base;
spin_lock_init(&lower->lock);
/* Enable timer, but disable interrupt */
spin_lock_init(&lower->read_lock);
oneshot_count_init(&lower->lh, NSEC_PER_SEC);
putreg32(1, lower->base + GOLDFISH_TIMER_CLEAR_INTERRUPT);
goldfish_timer_set_nsec(lower->base, UINT64_MAX);
/* Reset the timer registers. */
putreg32(1, base + GOLDFISH_TIMER_CLEAR_ALARM);
putreg32(1, base + GOLDFISH_TIMER_CLEAR_INTERRUPT);
putreg32(1, base + GOLDFISH_TIMER_IRQ_ENABLED);
irq_attach(irq, goldfish_timer_interrupt, lower);