mirror of
https://github.com/apache/nuttx.git
synced 2025-12-06 17:23:49 +08:00
arch/armv7r: Add armv7r clkdev timer driver.
This commit added armv7r clkdev timer driver. Signed-off-by: husong1 <husong1@xiaomi.com>
This commit is contained in:
@@ -27,6 +27,8 @@ endif # ARMV7R_GIC_EOIMODE
|
||||
config ARMV7R_HAVE_PTM
|
||||
bool
|
||||
default n
|
||||
select ONESHOT
|
||||
select ONESHOT_COUNT
|
||||
---help---
|
||||
Selected by the configuration tool if the architecture supports the
|
||||
per-processor Private Timers (PTMs)
|
||||
|
||||
@@ -49,52 +49,6 @@
|
||||
# define GIC_IRQ_TIMER GIC_IRQ_PTM
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
|
||||
/* This structure provides the private representation of the "lower-half"
|
||||
* driver state structure. This structure must be cast-compatible with the
|
||||
* oneshot_lowerhalf_s structure.
|
||||
*/
|
||||
|
||||
struct arm_timer_lowerhalf_s
|
||||
{
|
||||
struct oneshot_lowerhalf_s lh; /* Lower half operations */
|
||||
uint32_t freq; /* Timer working clock frequency(Hz) */
|
||||
|
||||
/* which cpu timer is running, -1 indicate timer stoppd */
|
||||
|
||||
int running;
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
static int arm_timer_maxdelay(struct oneshot_lowerhalf_s *lower,
|
||||
struct timespec *ts);
|
||||
static int arm_timer_start(struct oneshot_lowerhalf_s *lower,
|
||||
const struct timespec *ts);
|
||||
static int arm_timer_cancel(struct oneshot_lowerhalf_s *lower,
|
||||
struct timespec *ts);
|
||||
static int arm_timer_current(struct oneshot_lowerhalf_s *lower,
|
||||
struct timespec *ts);
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
static const struct oneshot_operations_s g_arm_timer_ops =
|
||||
{
|
||||
.max_delay = arm_timer_maxdelay,
|
||||
.start = arm_timer_start,
|
||||
.cancel = arm_timer_cancel,
|
||||
.current = arm_timer_current,
|
||||
};
|
||||
|
||||
static struct arm_timer_lowerhalf_s g_arm_timer_lowerhalf;
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
@@ -134,101 +88,42 @@ static inline void arm_timer_phy_set_irq_mask(bool mask)
|
||||
UP_ISB();
|
||||
}
|
||||
|
||||
static inline uint64_t nsec_from_count(uint64_t count, uint32_t freq)
|
||||
static int arm_timer_interrupt(int irq, void *regs, void *arg)
|
||||
{
|
||||
uint64_t sec = count / freq;
|
||||
uint64_t nsec = (count % freq) * NSEC_PER_SEC / freq;
|
||||
return sec * NSEC_PER_SEC + nsec;
|
||||
struct oneshot_lowerhalf_s *priv = (struct oneshot_lowerhalf_s *)arg;
|
||||
arm_timer_phy_set_absolute(UINT64_MAX);
|
||||
oneshot_process_callback(priv);
|
||||
return OK;
|
||||
}
|
||||
|
||||
static inline uint64_t nsec_to_count(uint32_t nsec, uint32_t freq)
|
||||
static clkcnt_t arm_oneshot_max_delay(struct oneshot_lowerhalf_s *lower)
|
||||
{
|
||||
return (uint64_t)nsec * freq / NSEC_PER_SEC;
|
||||
return UINT32_MAX;
|
||||
}
|
||||
|
||||
static inline uint64_t sec_to_count(uint32_t sec, uint32_t freq)
|
||||
static clkcnt_t arm_oneshot_current(struct oneshot_lowerhalf_s *lower)
|
||||
{
|
||||
return (uint64_t)sec * freq;
|
||||
/* We do not need memory barrier here. */
|
||||
|
||||
return arm_timer_phy_count();
|
||||
}
|
||||
|
||||
static int arm_timer_maxdelay(struct oneshot_lowerhalf_s *lower_,
|
||||
struct timespec *ts)
|
||||
static void arm_oneshot_start_absolute(struct oneshot_lowerhalf_s *lower,
|
||||
clkcnt_t expected)
|
||||
{
|
||||
uint64_t maxnsec = nsec_from_count(UINT64_MAX, arm_timer_get_freq());
|
||||
|
||||
ts->tv_sec = maxnsec / NSEC_PER_SEC;
|
||||
ts->tv_nsec = maxnsec % NSEC_PER_SEC;
|
||||
|
||||
return 0;
|
||||
arm_timer_phy_set_absolute(expected);
|
||||
}
|
||||
|
||||
static int arm_timer_start(struct oneshot_lowerhalf_s *lower_,
|
||||
const struct timespec *ts)
|
||||
static void arm_oneshot_start(struct oneshot_lowerhalf_s *lower,
|
||||
clkcnt_t delta)
|
||||
{
|
||||
struct arm_timer_lowerhalf_s *lower =
|
||||
(struct arm_timer_lowerhalf_s *)lower_;
|
||||
irqstate_t flags;
|
||||
uint64_t count;
|
||||
|
||||
flags = up_irq_save();
|
||||
|
||||
lower->running = this_cpu();
|
||||
|
||||
count = sec_to_count(ts->tv_sec, arm_timer_get_freq()) +
|
||||
nsec_to_count(ts->tv_nsec, arm_timer_get_freq());
|
||||
|
||||
arm_timer_phy_set_relative(count > UINT32_MAX ? UINT32_MAX : count);
|
||||
|
||||
arm_timer_phy_set_relative(delta);
|
||||
arm_timer_phy_set_irq_mask(false);
|
||||
|
||||
up_irq_restore(flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int arm_timer_cancel(struct oneshot_lowerhalf_s *lower_,
|
||||
struct timespec *ts)
|
||||
static void arm_oneshot_cancel(struct oneshot_lowerhalf_s *lower)
|
||||
{
|
||||
struct arm_timer_lowerhalf_s *lower =
|
||||
(struct arm_timer_lowerhalf_s *)lower_;
|
||||
irqstate_t flags;
|
||||
|
||||
flags = up_irq_save();
|
||||
|
||||
lower->running = -1;
|
||||
|
||||
arm_timer_phy_set_irq_mask(true);
|
||||
|
||||
up_irq_restore(flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int arm_timer_current(struct oneshot_lowerhalf_s *lower_,
|
||||
struct timespec *ts)
|
||||
{
|
||||
uint64_t nsec = nsec_from_count(arm_timer_phy_count(),
|
||||
arm_timer_get_freq());
|
||||
|
||||
ts->tv_sec = nsec / NSEC_PER_SEC;
|
||||
ts->tv_nsec = nsec % NSEC_PER_SEC;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int arm_timer_interrupt(int irq, void *context, void *arg)
|
||||
{
|
||||
struct arm_timer_lowerhalf_s *lower = arg;
|
||||
DEBUGASSERT(lower != NULL);
|
||||
|
||||
arm_timer_phy_set_irq_mask(true);
|
||||
|
||||
if (lower->running == this_cpu())
|
||||
{
|
||||
oneshot_process_callback(&lower->lh);
|
||||
}
|
||||
|
||||
return 0;
|
||||
arm_timer_phy_set_absolute(UINT64_MAX);
|
||||
}
|
||||
|
||||
static void arm_timer_initialize_per_cpu(unsigned int freq)
|
||||
@@ -240,29 +135,50 @@ static void arm_timer_initialize_per_cpu(unsigned int freq)
|
||||
arm_timer_set_freq(freq);
|
||||
}
|
||||
|
||||
arm_timer_phy_set_irq_mask(true);
|
||||
arm_timer_phy_set_absolute(UINT64_MAX);
|
||||
arm_timer_phy_enable(true);
|
||||
arm_timer_phy_set_irq_mask(false);
|
||||
|
||||
up_enable_irq(GIC_IRQ_TIMER);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
static const struct oneshot_operations_s g_arm_oneshot_ops =
|
||||
{
|
||||
.current = arm_oneshot_current,
|
||||
.start = arm_oneshot_start,
|
||||
.start_absolute = arm_oneshot_start_absolute,
|
||||
.cancel = arm_oneshot_cancel,
|
||||
.max_delay = arm_oneshot_max_delay,
|
||||
};
|
||||
|
||||
static struct oneshot_lowerhalf_s g_arm_oneshot_lowerhalf =
|
||||
{
|
||||
.ops = &g_arm_oneshot_ops
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
struct oneshot_lowerhalf_s *arm_timer_initialize(unsigned int freq)
|
||||
{
|
||||
struct arm_timer_lowerhalf_s *lower = &g_arm_timer_lowerhalf;
|
||||
struct oneshot_lowerhalf_s *lower = &g_arm_oneshot_lowerhalf;
|
||||
|
||||
/* The init freq is for trust-zone only since CNTFRQ is only
|
||||
* allowed to access in secure state.
|
||||
*/
|
||||
|
||||
arm_timer_initialize_per_cpu(freq);
|
||||
|
||||
lower->freq = arm_timer_get_freq();
|
||||
lower->lh.ops = &g_arm_timer_ops;
|
||||
lower->running = -1;
|
||||
oneshot_count_init(lower, arm_timer_get_freq());
|
||||
|
||||
irq_attach(GIC_IRQ_TIMER, arm_timer_interrupt, lower);
|
||||
|
||||
return (struct oneshot_lowerhalf_s *)lower;
|
||||
return lower;
|
||||
}
|
||||
|
||||
void arm_timer_secondary_init(unsigned int freq)
|
||||
|
||||
Reference in New Issue
Block a user