mirror of
https://github.com/apache/nuttx.git
synced 2026-08-01 20:28:58 +00:00
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:
parent
5296b8d3e3
commit
6f17f1ce81
1 changed files with 106 additions and 121 deletions
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue