arch/riscv: Add mtimer driver
Signed-off-by: Xiang Xiao <xiaoxiang@xiaomi.com>
This commit is contained in:
parent
d4978bfba4
commit
a90bdda1ae
306
arch/risc-v/src/common/riscv_mtimer.c
Normal file
306
arch/risc-v/src/common/riscv_mtimer.c
Normal file
@ -0,0 +1,306 @@
|
||||
/****************************************************************************
|
||||
* arch/risc-v/src/common/riscv_mtimer.c
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership. The
|
||||
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/irq.h>
|
||||
#include <nuttx/kmalloc.h>
|
||||
|
||||
#include "riscv_mtimer.h"
|
||||
#include "riscv_internal.h"
|
||||
|
||||
/****************************************************************************
|
||||
* 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 riscv_mtimer_lowerhalf_s
|
||||
{
|
||||
struct oneshot_lowerhalf_s lower;
|
||||
uintptr_t mtime;
|
||||
uintptr_t mtimecmp;
|
||||
uint64_t freq;
|
||||
uint64_t alarm;
|
||||
oneshot_callback_t callback;
|
||||
void *arg;
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
static int riscv_mtimer_max_delay(struct oneshot_lowerhalf_s *lower,
|
||||
struct timespec *ts);
|
||||
static int riscv_mtimer_start(struct oneshot_lowerhalf_s *lower,
|
||||
oneshot_callback_t callback, void *arg,
|
||||
const struct timespec *ts);
|
||||
static int riscv_mtimer_cancel(struct oneshot_lowerhalf_s *lower,
|
||||
struct timespec *ts);
|
||||
static int riscv_mtimer_current(struct oneshot_lowerhalf_s *lower,
|
||||
struct timespec *ts);
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
static const struct oneshot_operations_s g_riscv_mtimer_ops =
|
||||
{
|
||||
.max_delay = riscv_mtimer_max_delay,
|
||||
.start = riscv_mtimer_start,
|
||||
.cancel = riscv_mtimer_cancel,
|
||||
.current = riscv_mtimer_current,
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
static uint64_t riscv_mtimer_get_mtime(struct riscv_mtimer_lowerhalf_s *priv)
|
||||
{
|
||||
#ifdef CONFIG_ARCH_RV64
|
||||
return getreg64(priv->mtime);
|
||||
#else
|
||||
uint32_t hi;
|
||||
uint32_t lo;
|
||||
|
||||
do
|
||||
{
|
||||
hi = getreg32(priv->mtime + 4);
|
||||
lo = getreg32(priv->mtime);
|
||||
}
|
||||
while (getreg32(priv->mtime + 4) != hi);
|
||||
|
||||
return ((uint64_t)hi << 32) | lo;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void riscv_mtimer_set_mtimecmp(struct riscv_mtimer_lowerhalf_s *priv,
|
||||
uint64_t value)
|
||||
{
|
||||
#ifdef CONFIG_ARCH_RV64
|
||||
putreg64(value, priv->mtimecmp);
|
||||
#else
|
||||
putreg32(UINT32_MAX, priv->mtimecmp + 4);
|
||||
putreg32(value, priv->mtimecmp);
|
||||
putreg32(value >> 32, priv->mtimecmp + 4);
|
||||
#endif
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: riscv_mtimer_max_delay
|
||||
*
|
||||
* Description:
|
||||
* Determine the maximum delay of the one-shot timer
|
||||
*
|
||||
* 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();
|
||||
* 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.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int riscv_mtimer_max_delay(struct oneshot_lowerhalf_s *lower,
|
||||
struct timespec *ts)
|
||||
{
|
||||
ts->tv_sec = UINT32_MAX;
|
||||
ts->tv_nsec = NSEC_PER_SEC - 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: riscv_mtimer_start
|
||||
*
|
||||
* Description:
|
||||
* Start the oneshot timer
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero (OK) is returned on success; a negated errno value is returned
|
||||
* on failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int riscv_mtimer_start(struct oneshot_lowerhalf_s *lower,
|
||||
oneshot_callback_t callback, void *arg,
|
||||
const struct timespec *ts)
|
||||
{
|
||||
struct riscv_mtimer_lowerhalf_s *priv =
|
||||
(struct riscv_mtimer_lowerhalf_s *)lower;
|
||||
uint64_t mtime = riscv_mtimer_get_mtime(priv);
|
||||
|
||||
priv->alarm = mtime + ts->tv_sec * priv->freq +
|
||||
ts->tv_nsec * priv->freq / NSEC_PER_SEC;
|
||||
if (priv->alarm < mtime)
|
||||
{
|
||||
priv->alarm = UINT64_MAX;
|
||||
}
|
||||
|
||||
priv->callback = callback;
|
||||
priv->arg = arg;
|
||||
|
||||
riscv_mtimer_set_mtimecmp(priv, priv->alarm);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: riscv_mtimer_cancel
|
||||
*
|
||||
* Description:
|
||||
* Cancel the oneshot timer and return the time remaining on the timer.
|
||||
*
|
||||
* NOTE: This function may execute at a high rate with no timer running (as
|
||||
* when pre-emption is enabled and disabled).
|
||||
*
|
||||
* Input Parameters:
|
||||
* 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.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int riscv_mtimer_cancel(struct oneshot_lowerhalf_s *lower,
|
||||
struct timespec *ts)
|
||||
{
|
||||
struct riscv_mtimer_lowerhalf_s *priv =
|
||||
(struct riscv_mtimer_lowerhalf_s *)lower;
|
||||
uint64_t mtime;
|
||||
|
||||
riscv_mtimer_set_mtimecmp(priv, UINT64_MAX);
|
||||
|
||||
mtime = riscv_mtimer_get_mtime(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;
|
||||
priv->callback = NULL;
|
||||
priv->arg = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: riscv_mtimer_current
|
||||
*
|
||||
* Description:
|
||||
* Get the current time.
|
||||
*
|
||||
* Input Parameters:
|
||||
* 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.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int riscv_mtimer_current(struct oneshot_lowerhalf_s *lower,
|
||||
struct timespec *ts)
|
||||
{
|
||||
struct riscv_mtimer_lowerhalf_s *priv =
|
||||
(struct riscv_mtimer_lowerhalf_s *)lower;
|
||||
uint64_t mtime = riscv_mtimer_get_mtime(priv);
|
||||
uint64_t nsec = mtime * NSEC_PER_SEC / priv->freq;
|
||||
|
||||
ts->tv_sec = nsec / NSEC_PER_SEC;
|
||||
ts->tv_nsec = nsec % NSEC_PER_SEC;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int riscv_mtimer_interrupt(int irq, void *context, void *arg)
|
||||
{
|
||||
struct riscv_mtimer_lowerhalf_s *priv = arg;
|
||||
|
||||
riscv_mtimer_set_mtimecmp(priv, UINT64_MAX);
|
||||
if (priv->callback != NULL)
|
||||
{
|
||||
priv->callback(&priv->lower, priv->arg);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
struct oneshot_lowerhalf_s *
|
||||
riscv_mtimer_initialize(uintptr_t mtime, uintptr_t mtimecmp,
|
||||
int irq, uint64_t freq)
|
||||
{
|
||||
struct riscv_mtimer_lowerhalf_s *priv;
|
||||
|
||||
priv = kmm_zalloc(sizeof(*priv));
|
||||
if (priv != NULL)
|
||||
{
|
||||
priv->lower.ops = &g_riscv_mtimer_ops;
|
||||
priv->mtime = mtime;
|
||||
priv->mtimecmp = mtimecmp;
|
||||
priv->freq = freq;
|
||||
|
||||
riscv_mtimer_set_mtimecmp(priv, UINT64_MAX);
|
||||
irq_attach(irq, riscv_mtimer_interrupt, priv);
|
||||
up_enable_irq(irq);
|
||||
}
|
||||
|
||||
return (struct oneshot_lowerhalf_s *)priv;
|
||||
}
|
51
arch/risc-v/src/common/riscv_mtimer.h
Normal file
51
arch/risc-v/src/common/riscv_mtimer.h
Normal file
@ -0,0 +1,51 @@
|
||||
/****************************************************************************
|
||||
* arch/risc-v/src/common/riscv_mtimer.h
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership. The
|
||||
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __ARCH_RISCV_SRC_COMMON_RISCV_MTIMER_H
|
||||
#define __ARCH_RISCV_SRC_COMMON_RISCV_MTIMER_H
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/timers/oneshot.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Public Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define EXTERN extern "C"
|
||||
extern "C"
|
||||
{
|
||||
#else
|
||||
#define EXTERN extern
|
||||
#endif
|
||||
|
||||
struct oneshot_lowerhalf_s *
|
||||
riscv_mtimer_initialize(uintptr_t mtime, uintptr_t mtimecmp,
|
||||
int irq, uint64_t freq);
|
||||
|
||||
#undef EXTERN
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __ARCH_RISCV_SRC_COMMON_RISCV_MTIMER_H */
|
Loading…
Reference in New Issue
Block a user