You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by xi...@apache.org on 2024/07/24 02:06:59 UTC
(nuttx) branch master updated: risc-v/bl808: Add timer driver
This is an automated email from the ASF dual-hosted git repository.
xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git
The following commit(s) were added to refs/heads/master by this push:
new 049a6da098 risc-v/bl808: Add timer driver
049a6da098 is described below
commit 049a6da098dad6db4687d98a6e0cad1b9e62b9c7
Author: Henry Rovner <ro...@gmail.com>
AuthorDate: Thu Jul 18 07:19:39 2024 -0700
risc-v/bl808: Add timer driver
This change implements a driver for the hardware timer blocks on the BL808, as well as a config with the timer example enabled.
---
.../platforms/risc-v/bl808/boards/ox64/index.rst | 6 +
Documentation/platforms/risc-v/bl808/index.rst | 2 +-
arch/risc-v/include/bl808/irq.h | 4 +
arch/risc-v/src/bl808/Kconfig | 5 +
arch/risc-v/src/bl808/Make.defs | 2 +-
arch/risc-v/src/bl808/bl808_timer.c | 549 +++++++++++++++++++++
.../{hardware/bl808_memorymap.h => bl808_timer.h} | 33 +-
arch/risc-v/src/bl808/hardware/bl808_memorymap.h | 2 +
arch/risc-v/src/bl808/hardware/bl808_timer.h | 100 ++++
boards/risc-v/bl808/ox64/configs/timer/defconfig | 100 ++++
boards/risc-v/bl808/ox64/src/bl808_appinit.c | 9 +-
11 files changed, 789 insertions(+), 23 deletions(-)
diff --git a/Documentation/platforms/risc-v/bl808/boards/ox64/index.rst b/Documentation/platforms/risc-v/bl808/boards/ox64/index.rst
index 85d245ce7d..70e5fa48f3 100644
--- a/Documentation/platforms/risc-v/bl808/boards/ox64/index.rst
+++ b/Documentation/platforms/risc-v/bl808/boards/ox64/index.rst
@@ -150,3 +150,9 @@ spi
This configuration enables support for SPI0 and spitool.
By default, GPIO14 is MISO, 13 is MOSI, 15 is SCLK and 12 is SS.
Serial Console is enabled on UART3 at 2 Mbps.
+
+timer
+-----
+
+This configuration enables support for hardware timers and the timer example app.
+Serial Console is enabled on UART3 at 2 Mbps.
diff --git a/Documentation/platforms/risc-v/bl808/index.rst b/Documentation/platforms/risc-v/bl808/index.rst
index f8f9d95d44..c7c68bdbcf 100644
--- a/Documentation/platforms/risc-v/bl808/index.rst
+++ b/Documentation/platforms/risc-v/bl808/index.rst
@@ -52,7 +52,7 @@ I2C No
I2S No
PWM No
SPI Yes
-Timers No
+Timers Yes
UART Yes
USB No
=========== ======= ====================
diff --git a/arch/risc-v/include/bl808/irq.h b/arch/risc-v/include/bl808/irq.h
index 0b743f1063..752832bfcd 100644
--- a/arch/risc-v/include/bl808/irq.h
+++ b/arch/risc-v/include/bl808/irq.h
@@ -54,6 +54,8 @@
#define BL808_IRQ_UART3 (RISCV_IRQ_SEXT + BL808_IRQ_NUM_BASE + 4)
#define BL808_IRQ_SPI1 (RISCV_IRQ_SEXT + BL808_IRQ_NUM_BASE + 7)
#define BL808_IRQ_D0_IPC (RISCV_IRQ_SEXT + BL808_IRQ_NUM_BASE + 38)
+#define BL808_IRQ_TIMER1_CH0 (RISCV_IRQ_SEXT + BL808_IRQ_NUM_BASE + 61)
+#define BL808_IRQ_TIMER1_CH1 (RISCV_IRQ_SEXT + BL808_IRQ_NUM_BASE + 62)
#define BL808_IRQ_M0IC (RISCV_IRQ_SEXT + BL808_IRQ_NUM_BASE + 65)
/* M0 IRQs ******************************************************************/
@@ -63,5 +65,7 @@
#define BL808_IRQ_UART0 (RISCV_IRQ_SEXT + BL808_IRQ_NUM_BASE + BL808_M0_IRQ_OFFSET + 28)
#define BL808_IRQ_UART1 (RISCV_IRQ_SEXT + BL808_IRQ_NUM_BASE + BL808_M0_IRQ_OFFSET + 29)
#define BL808_IRQ_UART2 (RISCV_IRQ_SEXT + BL808_IRQ_NUM_BASE + BL808_M0_IRQ_OFFSET + 30)
+#define BL808_IRQ_TIMER0_CH0 (RISCV_IRQ_SEXT + BL808_IRQ_NUM_BASE + BL808_M0_IRQ_OFFSET + 36)
+#define BL808_IRQ_TIMER0_CH1 (RISCV_IRQ_SEXT + BL808_IRQ_NUM_BASE + BL808_M0_IRQ_OFFSET + 37)
#endif /* __ARCH_RISCV_INCLUDE_BL808_IRQ_H */
diff --git a/arch/risc-v/src/bl808/Kconfig b/arch/risc-v/src/bl808/Kconfig
index 0156783813..d534dedfc0 100644
--- a/arch/risc-v/src/bl808/Kconfig
+++ b/arch/risc-v/src/bl808/Kconfig
@@ -224,4 +224,9 @@ config BL808_SPI1_SS
endif
+config BL808_TIMERS
+ bool "Timers"
+ default n
+ select TIMER
+
endmenu
diff --git a/arch/risc-v/src/bl808/Make.defs b/arch/risc-v/src/bl808/Make.defs
index ffb276ace9..308c0e7603 100644
--- a/arch/risc-v/src/bl808/Make.defs
+++ b/arch/risc-v/src/bl808/Make.defs
@@ -28,4 +28,4 @@ HEAD_ASRC = bl808_head.S
CHIP_CSRCS = bl808_start.c bl808_irq_dispatch.c bl808_irq.c
CHIP_CSRCS += bl808_timerisr.c bl808_allocateheap.c
CHIP_CSRCS += bl808_gpio.c bl808_mm_init.c bl808_pgalloc.c bl808_serial.c
-CHIP_CSRCS += bl808_gpadc.c bl808_spi.c
+CHIP_CSRCS += bl808_gpadc.c bl808_spi.c bl808_timer.c
diff --git a/arch/risc-v/src/bl808/bl808_timer.c b/arch/risc-v/src/bl808/bl808_timer.c
new file mode 100644
index 0000000000..9a666a456f
--- /dev/null
+++ b/arch/risc-v/src/bl808/bl808_timer.c
@@ -0,0 +1,549 @@
+/****************************************************************************
+ * arch/risc-v/src/bl808/bl808_timer.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/config.h>
+#include <nuttx/arch.h>
+
+#include <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <debug.h>
+
+#include <nuttx/irq.h>
+#include <nuttx/timers/timer.h>
+#include <nuttx/fs/ioctl.h>
+#include <nuttx/serial/tioctl.h>
+
+#include "hardware/bl808_timer.h"
+#include "riscv_internal.h"
+#include "chip.h"
+#include "bl808_timer.h"
+
+#ifdef CONFIG_BL808_TIMERS
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define TIMER_GET_BLK(n) (n >= 2)
+#define TIMER_GET_CH(n) (n % 2)
+
+#define TIMER_CLK_SRC_XTAL 3
+#define TIMER_CLK_SRC_NONE 5
+
+#define XCLK_DIV 39 /* XCLK is 40 MHz, so divide by 40 */
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+enum bl808_timer_ch_e
+ {
+ TIMER0_CH0 = 0,
+ TIMER0_CH1 = 1,
+ TIMER1_CH0 = 2,
+ TIMER1_CH1 = 3
+ };
+
+struct bl808_timer_ch_s
+{
+ const struct timer_ops_s *ops;
+ enum bl808_timer_ch_e blk_ch;
+ tccb_t callback;
+ void *arg;
+ bool started;
+ uint32_t timeout;
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+int bl808_timer_start(FAR struct timer_lowerhalf_s *lower);
+int bl808_timer_stop(FAR struct timer_lowerhalf_s *lower);
+int bl808_timer_getstatus(FAR struct timer_lowerhalf_s *lower,
+ FAR struct timer_status_s *status);
+int bl808_timer_settimeout(FAR struct timer_lowerhalf_s *lower,
+ uint32_t timeout);
+void bl808_timer_setcallback(FAR struct timer_lowerhalf_s *lower,
+ CODE tccb_t callback, FAR void *arg);
+int bl808_timer_ioctl(FAR struct timer_lowerhalf_s *lower,
+ int cmd, unsigned long arg);
+int bl808_timer_maxtimeout(FAR struct timer_lowerhalf_s *lower,
+ FAR uint32_t *maxtimeout);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static struct timer_ops_s bl808_timer_ops =
+ {
+ .start = bl808_timer_start,
+ .stop = bl808_timer_stop,
+ .getstatus = bl808_timer_getstatus,
+ .settimeout = bl808_timer_settimeout,
+ .setcallback = bl808_timer_setcallback,
+ .ioctl = bl808_timer_ioctl,
+ .maxtimeout = bl808_timer_maxtimeout
+ };
+
+static struct bl808_timer_ch_s timer0_ch0 =
+ {
+ .ops = &bl808_timer_ops,
+ .blk_ch = TIMER0_CH0,
+ .callback = NULL,
+ .arg = NULL,
+ .started = false,
+ .timeout = 0
+ };
+
+static struct bl808_timer_ch_s timer0_ch1 =
+ {
+ .ops = &bl808_timer_ops,
+ .blk_ch = TIMER0_CH1,
+ .callback = NULL,
+ .arg = NULL,
+ .started = false,
+ .timeout = 0
+ };
+
+static struct bl808_timer_ch_s timer1_ch0 =
+ {
+ .ops = &bl808_timer_ops,
+ .blk_ch = TIMER1_CH0,
+ .callback = NULL,
+ .arg = NULL,
+ .started = false,
+ .timeout = 0
+ };
+
+static struct bl808_timer_ch_s timer1_ch1 =
+ {
+ .ops = &bl808_timer_ops,
+ .blk_ch = TIMER1_CH1,
+ .callback = NULL,
+ .arg = NULL,
+ .started = false,
+ .timeout = 0
+ };
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: timer_interrupt
+ *
+ * Description:
+ * Timer interrupt handler. Clears the interrupt and
+ * Calls the attached callback if there is one.
+ *
+ ****************************************************************************/
+
+static int __timer_interrupt(int irq, void *context, void *arg)
+{
+ struct bl808_timer_ch_s *priv = (struct bl808_timer_ch_s *)arg;
+ uint32_t next_interval = 0;
+
+ /* Clear IRQ */
+
+ switch (irq)
+ {
+ case BL808_IRQ_TIMER0_CH0:
+ modifyreg32(BL808_TIMER_CH0_ICLR(0), 0, TIMER_COMP0_INT);
+ break;
+
+ case BL808_IRQ_TIMER0_CH1:
+ modifyreg32(BL808_TIMER_CH1_ICLR(0), 0, TIMER_COMP0_INT);
+ break;
+
+ case BL808_IRQ_TIMER1_CH0:
+ modifyreg32(BL808_TIMER_CH0_ICLR(1), 0, TIMER_COMP0_INT);
+ break;
+
+ case BL808_IRQ_TIMER1_CH1:
+ modifyreg32(BL808_TIMER_CH1_ICLR(1), 0, TIMER_COMP0_INT);
+ break;
+
+ default:
+ return -EIO;
+ }
+
+ if (priv->callback != NULL)
+ {
+ if (priv->callback(&next_interval, priv->arg))
+ {
+ if (next_interval > 0)
+ {
+ bl808_timer_settimeout((struct timer_lowerhalf_s *)priv,
+ next_interval);
+ }
+
+ bl808_timer_start((struct timer_lowerhalf_s *)priv);
+ }
+ }
+
+ return OK;
+}
+
+/****************************************************************************
+ * Name: bl808_timer_start
+ *
+ * Description:
+ * Reset the time to the current timeout and start the timer.
+ *
+ ****************************************************************************/
+
+int bl808_timer_start(FAR struct timer_lowerhalf_s *lower)
+{
+ struct bl808_timer_ch_s *priv = (struct bl808_timer_ch_s *)lower;
+ if (TIMER_GET_CH(priv->blk_ch) == 0)
+ {
+ modifyreg32(BL808_TIMER_TCCR(TIMER_GET_BLK(priv->blk_ch)),
+ TIMER_CH0_CLKSEL_MASK,
+ TIMER_CLK_SRC_XTAL << TIMER_CH0_CLKSEL_SHIFT);
+
+ /* Clear timer */
+
+ modifyreg32(BL808_TIMER_EN_CLR(TIMER_GET_BLK(priv->blk_ch)),
+ 0, TIMER_CH0_CLR);
+
+ /* Wait for the counter to clear */
+
+ while (getreg32(BL808_TIMER_CH0_COUNTER(TIMER_GET_BLK(priv->blk_ch)))
+ != 0);
+
+ modifyreg32(BL808_TIMER_EN_CLR(TIMER_GET_BLK(priv->blk_ch)),
+ TIMER_CH0_CLR, 0);
+ }
+ else /* Channel 1 */
+ {
+ modifyreg32(BL808_TIMER_TCCR(TIMER_GET_BLK(priv->blk_ch)),
+ TIMER_CH1_CLKSEL_MASK,
+ TIMER_CLK_SRC_XTAL << TIMER_CH1_CLKSEL_SHIFT);
+
+ /* Clear timer */
+
+ modifyreg32(BL808_TIMER_EN_CLR(TIMER_GET_BLK(priv->blk_ch)),
+ 0, TIMER_CH1_CLR);
+
+ /* Wait for the counter to clear */
+
+ while (getreg32(BL808_TIMER_CH1_COUNTER(TIMER_GET_BLK(priv->blk_ch)))
+ != 0);
+
+ modifyreg32(BL808_TIMER_EN_CLR(TIMER_GET_BLK(priv->blk_ch)),
+ TIMER_CH1_CLR, 0);
+ }
+
+ priv->started = true;
+ return OK;
+}
+
+/****************************************************************************
+ * Name: bl808_timer_stop
+ *
+ * Description:
+ * Stop the timer.
+ *
+ ****************************************************************************/
+
+int bl808_timer_stop(FAR struct timer_lowerhalf_s *lower)
+{
+ struct bl808_timer_ch_s *priv = (struct bl808_timer_ch_s *)lower;
+
+ /* Timers are stopped by setting the input clock to NONE.
+ * This is done to allow calling timer_stop and then get
+ * the time left to timeout afterwards. If we used the
+ * timer enable bits, the counter would reset to 0 when stopped.
+ */
+
+ if (TIMER_GET_CH(priv->blk_ch) == 0)
+ {
+ modifyreg32(BL808_TIMER_TCCR(TIMER_GET_BLK(priv->blk_ch)),
+ TIMER_CH0_CLKSEL_MASK,
+ TIMER_CLK_SRC_NONE << TIMER_CH0_CLKSEL_SHIFT);
+ }
+ else
+ {
+ modifyreg32(BL808_TIMER_TCCR(TIMER_GET_BLK(priv->blk_ch)),
+ TIMER_CH0_CLKSEL_MASK,
+ TIMER_CLK_SRC_NONE << TIMER_CH1_CLKSEL_SHIFT);
+ }
+
+ priv->started = false;
+ return OK;
+}
+
+/****************************************************************************
+ * Name: bl808_timer_getstatus
+ *
+ * Description:
+ * Get current timer status. Returns to status parameter.
+ *
+ ****************************************************************************/
+
+int bl808_timer_getstatus(FAR struct timer_lowerhalf_s *lower,
+ FAR struct timer_status_s *status)
+{
+ struct bl808_timer_ch_s *priv = (struct bl808_timer_ch_s *)lower;
+ uint32_t current_count;
+
+ status->flags = priv->started
+ | ((priv->callback != NULL) << 1);
+ status->timeout = priv->timeout;
+
+ if (TIMER_GET_CH(priv->blk_ch) == 0)
+ {
+ current_count =
+ getreg32(BL808_TIMER_CH0_COUNTER(TIMER_GET_BLK(priv->blk_ch)));
+ }
+ else
+ {
+ current_count =
+ getreg32(BL808_TIMER_CH1_COUNTER(TIMER_GET_BLK(priv->blk_ch)));
+ }
+
+ status->timeleft = priv->timeout - current_count;
+
+ return OK;
+}
+
+/****************************************************************************
+ * Name: bl808_timer_settimeout
+ *
+ * Description:
+ * Set a new timeout value and reset the timer.
+ *
+ ****************************************************************************/
+
+int bl808_timer_settimeout(FAR struct timer_lowerhalf_s *lower,
+ uint32_t timeout)
+{
+ struct bl808_timer_ch_s *priv = (struct bl808_timer_ch_s *)lower;
+ if (TIMER_GET_CH(priv->blk_ch) == 0)
+ {
+ modifyreg32(BL808_TIMER_CH0_COMP0(TIMER_GET_BLK(priv->blk_ch)),
+ 0xffffffff, timeout);
+ priv->timeout = timeout;
+
+ /* Clock is needed to clear counters */
+
+ modifyreg32(BL808_TIMER_TCCR(TIMER_GET_BLK(priv->blk_ch)),
+ TIMER_CH0_CLKSEL_MASK,
+ TIMER_CLK_SRC_XTAL << TIMER_CH0_CLKSEL_SHIFT);
+
+ modifyreg32(BL808_TIMER_EN_CLR(TIMER_GET_BLK(priv->blk_ch)),
+ 0, TIMER_CH0_CLR);
+
+ while (getreg32(BL808_TIMER_CH0_COUNTER(TIMER_GET_BLK(priv->blk_ch)))
+ != 0);
+
+ /* Disable clock to stop timer from running after clear */
+
+ modifyreg32(BL808_TIMER_TCCR(TIMER_GET_BLK(priv->blk_ch)),
+ TIMER_CH0_CLKSEL_MASK,
+ TIMER_CLK_SRC_NONE << TIMER_CH0_CLKSEL_SHIFT);
+
+ modifyreg32(BL808_TIMER_EN_CLR(TIMER_GET_BLK(priv->blk_ch)),
+ TIMER_CH0_CLR, 0);
+ }
+ else
+ {
+ modifyreg32(BL808_TIMER_CH1_COMP0(TIMER_GET_BLK(priv->blk_ch)),
+ 0xffffffff, timeout);
+ priv->timeout = timeout;
+
+ /* Clock is needed to clear counters */
+
+ modifyreg32(BL808_TIMER_TCCR(TIMER_GET_BLK(priv->blk_ch)),
+ TIMER_CH1_CLKSEL_MASK,
+ TIMER_CLK_SRC_XTAL << TIMER_CH1_CLKSEL_SHIFT);
+
+ modifyreg32(BL808_TIMER_EN_CLR(TIMER_GET_BLK(priv->blk_ch)),
+ 0, TIMER_CH1_CLR);
+
+ while (getreg32(BL808_TIMER_CH1_COUNTER(TIMER_GET_BLK(priv->blk_ch)))
+ != 0);
+
+ /* Disable clock to stop timer from running after clear */
+
+ modifyreg32(BL808_TIMER_TCCR(TIMER_GET_BLK(priv->blk_ch)),
+ TIMER_CH1_CLKSEL_MASK,
+ TIMER_CLK_SRC_NONE << TIMER_CH1_CLKSEL_SHIFT);
+
+ modifyreg32(BL808_TIMER_EN_CLR(TIMER_GET_BLK(priv->blk_ch)),
+ TIMER_CH1_CLR, 0);
+ }
+
+ return OK;
+}
+
+/****************************************************************************
+ * Name: bl808_timer_setcallback
+ *
+ * Description:
+ * Sets a new callback to be run on timeout.
+ *
+ ****************************************************************************/
+
+void bl808_timer_setcallback(FAR struct timer_lowerhalf_s *lower,
+ CODE tccb_t callback, FAR void *arg)
+{
+ struct bl808_timer_ch_s *priv = (struct bl808_timer_ch_s *)lower;
+ priv->callback = callback;
+ priv->arg = arg;
+}
+
+/****************************************************************************
+ * Name: bl808_timer_ioctl
+ *
+ * Description:
+ * Handle ioctl commands not recognized by upper-half.
+ *
+ ****************************************************************************/
+
+int bl808_timer_ioctl(FAR struct timer_lowerhalf_s *lower,
+ int cmd, unsigned long arg)
+{
+ /* No additional ioctl commands implemented */
+
+ return -EIO;
+}
+
+/****************************************************************************
+ * Name: bl808_timer_maxtimeout
+ *
+ * Description:
+ * Return the maximum allowed timeout value.
+ * Returns to maxtimeout parameter.
+ *
+ ****************************************************************************/
+
+int bl808_timer_maxtimeout(FAR struct timer_lowerhalf_s *lower,
+ FAR uint32_t *maxtimeout)
+{
+ /* Timer comparators are 32-bit */
+
+ *maxtimeout = 0xffffffff;
+
+ return OK;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+int bl808_timer_init(void)
+{
+ int ret = OK;
+
+ /* The registered devpaths follow the recommended naming
+ * convention, i.e. timer0, timer1, etc. The order chosen
+ * for the numbering is the same as for bl808_timer_ch_e.
+ */
+
+ /* Timer 0, channel 0 */
+
+ modifyreg32(BL808_TIMER_TCCR(0), TIMER_CH0_CLKSEL_MASK,
+ TIMER_CLK_SRC_NONE << TIMER_CH0_CLKSEL_SHIFT);
+ modifyreg32(BL808_TIMER_CH0_IE(0), 0, TIMER_COMP0_INT);
+ modifyreg32(BL808_TIMER_DIV(0), TIMER_CH0_DIV_MASK,
+ (XCLK_DIV << TIMER_CH0_DIV_SHIFT));
+ modifyreg32(BL808_TIMER_MODE(0), 0, TIMER_CH0_MODE);
+ modifyreg32(BL808_TIMER_EN_CLR(0), 0, TIMER_CH0_EN);
+ ret |= irq_attach(BL808_IRQ_TIMER0_CH0, __timer_interrupt,
+ (void *)&timer0_ch0);
+ if (ret == OK)
+ {
+ up_enable_irq(BL808_IRQ_TIMER0_CH0);
+ }
+
+ timer_register("/dev/timer0",
+ (struct timer_lowerhalf_s *)&timer0_ch0);
+
+ /* Timer 0, channel 1 */
+
+ modifyreg32(BL808_TIMER_TCCR(0), TIMER_CH1_CLKSEL_MASK,
+ TIMER_CLK_SRC_NONE << TIMER_CH1_CLKSEL_SHIFT);
+ modifyreg32(BL808_TIMER_CH1_IE(0), 0, TIMER_COMP0_INT);
+ modifyreg32(BL808_TIMER_DIV(0), TIMER_CH1_DIV_MASK,
+ (XCLK_DIV << TIMER_CH1_DIV_SHIFT));
+ modifyreg32(BL808_TIMER_MODE(0), 0, TIMER_CH1_MODE);
+ modifyreg32(BL808_TIMER_EN_CLR(0), 0, TIMER_CH1_EN);
+ ret |= irq_attach(BL808_IRQ_TIMER0_CH1, __timer_interrupt,
+ (void *)&timer0_ch1);
+ if (ret == OK)
+ {
+ up_enable_irq(BL808_IRQ_TIMER0_CH1);
+ }
+
+ timer_register("/dev/timer1",
+ (struct timer_lowerhalf_s *)&timer0_ch1);
+
+ /* Timer 1, channel 0 */
+
+ modifyreg32(BL808_TIMER_TCCR(1), TIMER_CH0_CLKSEL_MASK,
+ TIMER_CLK_SRC_NONE << TIMER_CH0_CLKSEL_SHIFT);
+ modifyreg32(BL808_TIMER_CH0_IE(1), 0, TIMER_COMP0_INT);
+ modifyreg32(BL808_TIMER_DIV(1), TIMER_CH0_DIV_MASK,
+ (XCLK_DIV << TIMER_CH0_DIV_SHIFT));
+ modifyreg32(BL808_TIMER_MODE(1), 0, TIMER_CH0_MODE);
+ modifyreg32(BL808_TIMER_EN_CLR(1), 0, TIMER_CH0_EN);
+ ret |= irq_attach(BL808_IRQ_TIMER1_CH0, __timer_interrupt,
+ (void *)&timer1_ch0);
+ if (ret == OK)
+ {
+ up_enable_irq(BL808_IRQ_TIMER1_CH0);
+ }
+
+ timer_register("/dev/timer2",
+ (struct timer_lowerhalf_s *)&timer1_ch0);
+
+ /* Timer 1, channel 1 */
+
+ modifyreg32(BL808_TIMER_TCCR(1), TIMER_CH1_CLKSEL_MASK,
+ TIMER_CLK_SRC_NONE << TIMER_CH1_CLKSEL_SHIFT);
+ modifyreg32(BL808_TIMER_CH1_IE(1), 0, TIMER_COMP0_INT);
+ modifyreg32(BL808_TIMER_DIV(1), TIMER_CH1_DIV_MASK,
+ (XCLK_DIV << TIMER_CH1_DIV_SHIFT));
+ modifyreg32(BL808_TIMER_MODE(1), 0, TIMER_CH1_MODE);
+ modifyreg32(BL808_TIMER_EN_CLR(1), 0, TIMER_CH1_EN);
+ ret |= irq_attach(BL808_IRQ_TIMER1_CH1, __timer_interrupt,
+ (void *)&timer1_ch1);
+ if (ret == OK)
+ {
+ up_enable_irq(BL808_IRQ_TIMER1_CH1);
+ }
+
+ timer_register("/dev/timer3",
+ (struct timer_lowerhalf_s *)&timer1_ch1);
+
+ return ret;
+}
+
+#endif /* CONFIG_BL808_TIMERS */
diff --git a/arch/risc-v/src/bl808/hardware/bl808_memorymap.h b/arch/risc-v/src/bl808/bl808_timer.h
similarity index 57%
copy from arch/risc-v/src/bl808/hardware/bl808_memorymap.h
copy to arch/risc-v/src/bl808/bl808_timer.h
index aaff526633..6c7f5cfb1a 100644
--- a/arch/risc-v/src/bl808/hardware/bl808_memorymap.h
+++ b/arch/risc-v/src/bl808/bl808_timer.h
@@ -1,5 +1,5 @@
/****************************************************************************
- * arch/risc-v/src/bl808/hardware/bl808_memorymap.h
+ * arch/risc-v/src/bl808/bl808_timer.h
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
@@ -18,27 +18,22 @@
*
****************************************************************************/
-#ifndef __ARCH_RISCV_SRC_BL808_HARDWARE_BL808_MEMORYMAP_H
-#define __ARCH_RISCV_SRC_BL808_HARDWARE_BL808_MEMORYMAP_H
+#ifndef __ARCH_RISC_V_SRC_BL808_BL808_TIMER_H
+#define __ARCH_RISC_V_SRC_BL808_BL808_TIMER_H
/****************************************************************************
- * Pre-processor Definitions
+ * Public Functions Prototypes
****************************************************************************/
-/* Register Base Address ****************************************************/
+/****************************************************************************
+ * Name: bl808_timer_init
+ *
+ * Description:
+ * Initialize timer hardware and register character drivers
+ * for enabled timer channels.
+ *
+ ****************************************************************************/
-#define BL808_GLB_BASE 0x20000000ul
-#define BL808_M0IC_BASE 0x20000050ul
-#define BL808_GPIO_BASE 0x200008c4ul
-#define BL808_GPADC_BASE 0x20002000ul
-#define BL808_UART0_BASE 0x2000a000ul
-#define BL808_UART1_BASE 0x2000a100ul
-#define BL808_SPI0_BASE 0x2000a200ul
-#define BL808_UART2_BASE 0x2000aa00ul
-#define BL808_AON_BASE 0x2000f000ul
-#define BL808_UART3_BASE 0x30002000ul
-#define BL808_MM_GLB_BASE 0x30007000ul
-#define BL808_SPI1_BASE 0x30008000ul
-#define BL808_PLIC_BASE 0xe0000000ul
+int bl808_timer_init(void);
-#endif /* __ARCH_RISCV_SRC_BL808_HARDWARE_BL808_MEMORYMAP_H */
+#endif /* __ARCH_RISC_V_SRC_BL808_BL808_TIMER_H */
diff --git a/arch/risc-v/src/bl808/hardware/bl808_memorymap.h b/arch/risc-v/src/bl808/hardware/bl808_memorymap.h
index aaff526633..397e0809ea 100644
--- a/arch/risc-v/src/bl808/hardware/bl808_memorymap.h
+++ b/arch/risc-v/src/bl808/hardware/bl808_memorymap.h
@@ -34,11 +34,13 @@
#define BL808_UART0_BASE 0x2000a000ul
#define BL808_UART1_BASE 0x2000a100ul
#define BL808_SPI0_BASE 0x2000a200ul
+#define BL808_TIMER0_BASE 0x2000a500ul
#define BL808_UART2_BASE 0x2000aa00ul
#define BL808_AON_BASE 0x2000f000ul
#define BL808_UART3_BASE 0x30002000ul
#define BL808_MM_GLB_BASE 0x30007000ul
#define BL808_SPI1_BASE 0x30008000ul
+#define BL808_TIMER1_BASE 0x30009000ul
#define BL808_PLIC_BASE 0xe0000000ul
#endif /* __ARCH_RISCV_SRC_BL808_HARDWARE_BL808_MEMORYMAP_H */
diff --git a/arch/risc-v/src/bl808/hardware/bl808_timer.h b/arch/risc-v/src/bl808/hardware/bl808_timer.h
new file mode 100644
index 0000000000..01f342e9c6
--- /dev/null
+++ b/arch/risc-v/src/bl808/hardware/bl808_timer.h
@@ -0,0 +1,100 @@
+/****************************************************************************
+ * arch/risc-v/src/bl808/hardware/bl808_timer.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_BL808_HARDWARE_BL808_TIMER_H
+#define __ARCH_RISCV_SRC_BL808_HARDWARE_BL808_TIMER_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include "bl808_memorymap.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define BL808_TIMER_BASE(n) ((n == 0) ? BL808_TIMER0_BASE \
+ : BL808_TIMER1_BASE)
+
+/* Register offsets *********************************************************/
+
+#define BL808_TIMER_TCCR_OFFSET 0x00
+#define BL808_TIMER_CH0_COMP0_OFFSET 0x10
+#define BL808_TIMER_CH1_COMP0_OFFSET 0x1c
+#define BL808_TIMER_CH0_COUNTER_OFFSET 0x2c
+#define BL808_TIMER_CH1_COUNTER_OFFSET 0x30
+#define BL808_TIMER_CH0_IE_OFFSET 0x44
+#define BL808_TIMER_CH1_IE_OFFSET 0x48
+#define BL808_TIMER_CH0_ICLR_OFFSET 0x78
+#define BL808_TIMER_CH1_ICLR_OFFSET 0x7c
+#define BL808_TIMER_EN_CLR_OFFSET 0x84
+#define BL808_TIMER_MODE_OFFSET 0x88
+#define BL808_TIMER_DIV_OFFSET 0xBC
+
+/* Register definitions *****************************************************/
+
+#define BL808_TIMER_TCCR(n) (BL808_TIMER_BASE(n) + BL808_TIMER_TCCR_OFFSET)
+#define BL808_TIMER_CH0_COMP0(n) (BL808_TIMER_BASE(n) + BL808_TIMER_CH0_COMP0_OFFSET)
+#define BL808_TIMER_CH1_COMP0(n) (BL808_TIMER_BASE(n) + BL808_TIMER_CH1_COMP0_OFFSET)
+#define BL808_TIMER_CH0_COUNTER(n) (BL808_TIMER_BASE(n) + BL808_TIMER_CH0_COUNTER_OFFSET)
+#define BL808_TIMER_CH1_COUNTER(n) (BL808_TIMER_BASE(n) + BL808_TIMER_CH1_COUNTER_OFFSET)
+#define BL808_TIMER_CH0_IE(n) (BL808_TIMER_BASE(n) + BL808_TIMER_CH0_IE_OFFSET)
+#define BL808_TIMER_CH1_IE(n) (BL808_TIMER_BASE(n) + BL808_TIMER_CH1_IE_OFFSET)
+#define BL808_TIMER_CH0_ICLR(n) (BL808_TIMER_BASE(n) + BL808_TIMER_CH0_ICLR_OFFSET)
+#define BL808_TIMER_CH1_ICLR(n) (BL808_TIMER_BASE(n) + BL808_TIMER_CH1_ICLR_OFFSET)
+#define BL808_TIMER_EN_CLR(n) (BL808_TIMER_BASE(n) + BL808_TIMER_EN_CLR_OFFSET)
+#define BL808_TIMER_MODE(n) (BL808_TIMER_BASE(n) + BL808_TIMER_MODE_OFFSET)
+#define BL808_TIMER_DIV(n) (BL808_TIMER_BASE(n) + BL808_TIMER_DIV_OFFSET)
+
+/* Register bit definitions *************************************************/
+
+/* TIMER_TCCR */
+
+#define TIMER_CH0_CLKSEL_SHIFT (0)
+#define TIMER_CH0_CLKSEL_MASK (0xf << TIMER_CH0_CLKSEL_SHIFT)
+#define TIMER_CH1_CLKSEL_SHIFT (4)
+#define TIMER_CH1_CLKSEL_MASK (0xf << TIMER_CH1_CLKSEL_SHIFT)
+
+/* TIMER_CH(0/1)_I(E/CLR) */
+
+#define TIMER_COMP0_INT (1 << 0)
+
+/* TIMER_EN_CLR */
+
+#define TIMER_CH0_EN (1 << 1)
+#define TIMER_CH1_EN (1 << 2)
+#define TIMER_CH0_CLR (1 << 5)
+#define TIMER_CH1_CLR (1 << 6)
+
+/* TIMER_MODE */
+
+#define TIMER_CH0_MODE (1 << 1)
+#define TIMER_CH1_MODE (1 << 2)
+
+/* TIMER_DIV */
+
+#define TIMER_CH0_DIV_SHIFT (8)
+#define TIMER_CH0_DIV_MASK (0xff << TIMER_CH0_DIV_SHIFT)
+#define TIMER_CH1_DIV_SHIFT (16)
+#define TIMER_CH1_DIV_MASK (0xff << TIMER_CH1_DIV_SHIFT)
+
+#endif /* __ARCH_RISCV_SRC_BL808_HARDWARE_BL808_TIMER_H */
diff --git a/boards/risc-v/bl808/ox64/configs/timer/defconfig b/boards/risc-v/bl808/ox64/configs/timer/defconfig
new file mode 100644
index 0000000000..351387af2e
--- /dev/null
+++ b/boards/risc-v/bl808/ox64/configs/timer/defconfig
@@ -0,0 +1,100 @@
+#
+# This file is autogenerated: PLEASE DO NOT EDIT IT.
+#
+# You can use "make menuconfig" to make any modifications to the installed .config file.
+# You can then do "make savedefconfig" to generate a new defconfig file that includes your
+# modifications.
+#
+# CONFIG_DISABLE_OS_API is not set
+# CONFIG_NSH_DISABLE_LOSMART is not set
+# CONFIG_STANDARD_SERIAL is not set
+CONFIG_ARCH="risc-v"
+CONFIG_ARCH_ADDRENV=y
+CONFIG_ARCH_BOARD="ox64"
+CONFIG_ARCH_BOARD_BL808_OX64=y
+CONFIG_ARCH_CHIP="bl808"
+CONFIG_ARCH_CHIP_BL808=y
+CONFIG_ARCH_DATA_NPAGES=128
+CONFIG_ARCH_DATA_VBASE=0x80100000
+CONFIG_ARCH_HEAP_NPAGES=128
+CONFIG_ARCH_HEAP_VBASE=0x80200000
+CONFIG_ARCH_INTERRUPTSTACK=2048
+CONFIG_ARCH_KERNEL_STACKSIZE=3072
+CONFIG_ARCH_PGPOOL_MAPPING=y
+CONFIG_ARCH_PGPOOL_PBASE=0x50600000
+CONFIG_ARCH_PGPOOL_SIZE=4194304
+CONFIG_ARCH_PGPOOL_VBASE=0x50600000
+CONFIG_ARCH_RISCV=y
+CONFIG_ARCH_STACKDUMP=y
+CONFIG_ARCH_TEXT_NPAGES=128
+CONFIG_ARCH_TEXT_VBASE=0x80000000
+CONFIG_ARCH_USE_MMU=y
+CONFIG_ARCH_USE_MPU=y
+CONFIG_ARCH_USE_S_MODE=y
+CONFIG_BL808_TIMERS=y
+CONFIG_BL808_UART0=y
+CONFIG_BL808_UART1=y
+CONFIG_BL808_UART2=y
+CONFIG_BL808_UART3=y
+CONFIG_BOARDCTL_ROMDISK=y
+CONFIG_BOARD_LATE_INITIALIZE=y
+CONFIG_BOARD_LOOPSPERMSEC=1120
+CONFIG_BUILD_KERNEL=y
+CONFIG_DEBUG_ASSERTIONS=y
+CONFIG_DEBUG_ASSERTIONS_EXPRESSION=y
+CONFIG_DEBUG_FEATURES=y
+CONFIG_DEBUG_FULLOPT=y
+CONFIG_DEBUG_SYMBOLS=y
+CONFIG_DEV_ZERO=y
+CONFIG_ELF=y
+CONFIG_EXAMPLES_HELLO=m
+CONFIG_EXAMPLES_TIMER=y
+CONFIG_FS_PROCFS=y
+CONFIG_FS_ROMFS=y
+CONFIG_IDLETHREAD_STACKSIZE=3072
+CONFIG_INIT_FILEPATH="/system/bin/init"
+CONFIG_INIT_MOUNT=y
+CONFIG_INIT_MOUNT_FLAGS=0x1
+CONFIG_INIT_MOUNT_TARGET="/system/bin"
+CONFIG_INIT_STACKSIZE=3072
+CONFIG_INTELHEX_BINARY=y
+CONFIG_LIBC_ENVPATH=y
+CONFIG_LIBC_EXECFUNCS=y
+CONFIG_LIBC_PERROR_STDOUT=y
+CONFIG_LIBC_STRERROR=y
+CONFIG_MEMSET_64BIT=y
+CONFIG_MEMSET_OPTSPEED=y
+CONFIG_MM_PGALLOC=y
+CONFIG_NFILE_DESCRIPTORS_PER_BLOCK=6
+CONFIG_NSH_ARCHINIT=y
+CONFIG_NSH_FILEIOSIZE=512
+CONFIG_NSH_FILE_APPS=y
+CONFIG_NSH_READLINE=y
+CONFIG_PATH_INITIAL="/system/bin"
+CONFIG_RAM_SIZE=1048576
+CONFIG_RAM_START=0x50200000
+CONFIG_READLINE_CMD_HISTORY=y
+CONFIG_RR_INTERVAL=200
+CONFIG_SCHED_HAVE_PARENT=y
+CONFIG_SCHED_LPWORK=y
+CONFIG_SCHED_WAITPID=y
+CONFIG_STACK_COLORATION=y
+CONFIG_START_MONTH=12
+CONFIG_START_YEAR=2021
+CONFIG_SYMTAB_ORDEREDBYNAME=y
+CONFIG_SYSTEM_NSH=y
+CONFIG_SYSTEM_NSH_PROGNAME="init"
+CONFIG_TESTING_GETPRIME=y
+CONFIG_TESTING_OSTEST=y
+CONFIG_UART0_BAUD=2000000
+CONFIG_UART0_BITS=7
+CONFIG_UART1_BAUD=2000000
+CONFIG_UART1_BITS=7
+CONFIG_UART2_BAUD=2000000
+CONFIG_UART2_BITS=7
+CONFIG_UART3_BAUD=2000000
+CONFIG_UART3_BITS=7
+CONFIG_UART3_SERIAL_CONSOLE=y
+CONFIG_USEC_PER_TICK=1000
+CONFIG_USERLED=y
+CONFIG_USERLED_LOWER=y
diff --git a/boards/risc-v/bl808/ox64/src/bl808_appinit.c b/boards/risc-v/bl808/ox64/src/bl808_appinit.c
index 9f0305bcbd..7236b5e598 100644
--- a/boards/risc-v/bl808/ox64/src/bl808_appinit.c
+++ b/boards/risc-v/bl808/ox64/src/bl808_appinit.c
@@ -41,6 +41,9 @@
#if defined(CONFIG_BL808_SPI0) || defined(CONFIG_BL808_SPI1)
#include "bl808_spi.h"
#endif
+#ifdef CONFIG_BL808_TIMERS
+#include "bl808_timer.h"
+#endif
#include "bl808_gpadc.h"
/****************************************************************************
@@ -168,9 +171,7 @@ void board_late_initialize(void)
/* Perform board-specific initialization */
#ifdef CONFIG_BL808_GPADC
-
bl808_gpadc_init();
-
#endif
#ifdef CONFIG_BL808_SPI0
@@ -183,6 +184,10 @@ void board_late_initialize(void)
spi_register(spi1, 1);
#endif
+#ifdef CONFIG_BL808_TIMERS
+ bl808_timer_init();
+#endif
+
#ifdef CONFIG_NSH_ARCHINIT
mount(NULL, "/proc", "procfs", 0, NULL);