aboutsummaryrefslogtreecommitdiff
path: root/board/thead/light-c910/timer.c
diff options
context:
space:
mode:
authorthead_admin <occ_thead@service.alibaba.com>2022-11-22 15:50:04 +0800
committerthead_admin <occ_thead@service.alibaba.com>2022-11-22 15:50:04 +0800
commit0c8e009c3a52c6a29b00cf70d368d5c082639197 (patch)
treea4389b0f036807156e36409123b58cbf3c78e656 /board/thead/light-c910/timer.c
parent43db9e00d5837c100c0b2fbbee64a08ab807d1e0 (diff)
Linux_SDK_V1.0.2Linux_SDK_V1.0.2
Diffstat (limited to 'board/thead/light-c910/timer.c')
-rw-r--r--board/thead/light-c910/timer.c224
1 files changed, 224 insertions, 0 deletions
diff --git a/board/thead/light-c910/timer.c b/board/thead/light-c910/timer.c
new file mode 100644
index 00000000..1734890e
--- /dev/null
+++ b/board/thead/light-c910/timer.c
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2017-2020 Alibaba Group Holding Limited
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/types.h>
+#include <thead/clock_config.h>
+#include <linux/bitops.h>
+#include <asm/arch-thead/light-iopmp.h>
+#include <asm/arch-thead/light-plic.h>
+
+#define DW_TIMER0_BASE 0xffefc32000
+#define DW_TIMER0_TLC_REG (DW_TIMER0_BASE + 0x00) /* Offset: 0x000 (R/W) TimerLoadCount */
+#define DW_TIMER0_TCV_REG (DW_TIMER0_BASE + 0X04) /* Offset: 0x004 (R/ ) TimerCurrentValue */
+#define DW_TIMER0_TCR_REG (DW_TIMER0_BASE + 0X08) /* Offset: 0x008 (R/W) TimerControlReg */
+#define DW_TIMER0_TEOI_REG (DW_TIMER0_BASE + 0X0C) /* Offset: 0x00c (R/ ) TimerEOI */
+#define DW_TIMER0_TIS_REG (DW_TIMER0_BASE + 0X10) /* Offset: 0x010 (R/ ) TimerIntStatus */
+
+/*! Timer Int Status, offset: 0x10 */
+#define DW_TIMER_INT_STATUS_Pos (0U)
+#define DW_TIMER_INT_STATUS_Msk (0x1U << DW_TIMER_INT_STATUS_Pos)
+#define DW_TIMER_INT_STATUS_EN DW_TIMER_INT_STATUS_Msk
+
+/*! Timer1 Control Reg, offset: 0x08 */
+#define DW_TIMER_CTL_ENABLE_SEL_Pos (0U)
+#define DW_TIMER_CTL_ENABLE_SEL_Msk (0x1U << DW_TIMER_CTL_ENABLE_SEL_Pos)
+#define DW_TIMER_CTL_ENABLE_SEL_EN DW_TIMER_CTL_ENABLE_SEL_Msk
+
+#define DW_TIMER_CTL_MODE_SEL_Pos (1U)
+#define DW_TIMER_CTL_MODE_SEL_Msk (0x1U << DW_TIMER_CTL_MODE_SEL_Pos)
+#define DW_TIMER_CTL_MODE_SEL_EN DW_TIMER_CTL_MODE_SEL_Msk
+
+#define DW_TIMER_CTL_INT_MASK_Pos (2U)
+#define DW_TIMER_CTL_INT_MASK_Msk (0x1U << DW_TIMER_CTL_INT_MASK_Pos)
+#define DW_TIMER_CTL_INT_MAKS_EN DW_TIMER_CTL_INT_MASK_Msk
+
+#define DW_TIMER_CTL_HARD_TRIG_Pos (4U)
+#define DW_TIMER_CTL_HARD_TRIG_Msk (0x1U << DW_TIMER_CTL_HARD_TRIG_Pos)
+#define DW_TIMER_CTL_HARD_TRIG_EN DW_TIMER_CTL_HARD_TRIG_Msk
+
+/*! Timer EOI, offset: 0x0c */
+#define DW_TIMER_EOI_REG_Pos (0U)
+#define DW_TIMER_EOI_REG_Msk (0x1U << DW_TIMER_EOI_REG_Pos)
+#define DW_TIMER_EOI_REG_EN DW_TIMER_EOI_REG_Msk
+
+#define TIMER0_IRQ_NUM 16
+#define TIMER0_FREQ_HZ 125000000U
+#define DW_TIMER_GET_RELOAD_VAL(_tim_, _frq_) ((_tim_ < 25000U) ? ((_frq_ * _tim_) / 1000U) : (_frq_ * (_tim_ / 1000U)))
+
+static int time_user_defined_flag = 0;
+
+static void csi_timer_stop(void);
+
+static inline u32 dw_timer_get_int_status(void)
+{
+ return (readl((void __iomem *)DW_TIMER0_TIS_REG) & DW_TIMER_INT_STATUS_EN) ? 1 : 0;
+}
+
+static inline void dw_timer_clear_irq(void)
+{
+ readl((void __iomem *)DW_TIMER0_TEOI_REG);
+}
+
+static inline void dw_timer_write_load(uint32_t value)
+{
+ writel(value, (void __iomem *)DW_TIMER0_TLC_REG);
+}
+
+static inline void dw_timer_set_mode_load(void)
+{
+ writel((readl((void __iomem *)DW_TIMER0_TCR_REG) | DW_TIMER_CTL_MODE_SEL_EN), (void __iomem *)DW_TIMER0_TCR_REG);
+}
+
+static inline void dw_timer_set_disable(void)
+{
+ u32 data = readl((void __iomem *)DW_TIMER0_TCR_REG);
+
+ data &= ~DW_TIMER_CTL_ENABLE_SEL_EN;
+ writel(data, (void __iomem *)DW_TIMER0_TCR_REG);
+}
+
+static inline void dw_timer_set_enable(void)
+{
+ u32 data = readl((void __iomem *)DW_TIMER0_TCR_REG);
+
+ data |= DW_TIMER_CTL_ENABLE_SEL_EN;
+ writel(data, (void __iomem *)DW_TIMER0_TCR_REG);
+}
+
+static inline void dw_timer_set_unmask(void)
+{
+ u32 data = readl((void __iomem *)DW_TIMER0_TCR_REG);
+
+ data &= ~DW_TIMER_CTL_INT_MAKS_EN;
+ writel(data, (void __iomem *)DW_TIMER0_TCR_REG);
+}
+
+static inline void dw_timer_set_mask(void)
+{
+ u32 data = readl((void __iomem *)DW_TIMER0_TCR_REG);
+
+ data |= DW_TIMER_CTL_INT_MAKS_EN;
+ writel(data, (void __iomem *)DW_TIMER0_TCR_REG);
+}
+
+static void dw_timer_irq_handler(void)
+{
+ debug("[%s,%d]\n", __func__, __LINE__);
+ if (dw_timer_get_int_status()) {
+ dw_timer_clear_irq();
+ csi_timer_stop();
+ debug("[%s,%d]\n", __func__, __LINE__);
+ time_user_defined_flag = 1;
+ }
+}
+
+static inline void dw_timer_reset_register(void)
+{
+ writel(0, (void __iomem *)DW_TIMER0_TLC_REG);
+ writel(0, (void __iomem *)DW_TIMER0_TCV_REG);
+}
+
+static int csi_timer_start(u32 timeout_us)
+{
+ u32 timer_freq = TIMER0_FREQ_HZ;
+ u32 tmp_load = DW_TIMER_GET_RELOAD_VAL(timeout_us, timer_freq);
+
+ dw_timer_set_mode_load();
+
+ //FIXME: no less than 10
+ if (tmp_load < 10)
+ tmp_load = 10;
+
+ dw_timer_write_load(tmp_load);
+
+ dw_timer_set_disable();
+ dw_timer_set_enable();
+ dw_timer_set_unmask();
+
+ return 0;
+}
+
+static void csi_timer_stop(void)
+{
+ dw_timer_set_mask();
+ dw_timer_set_disable();
+}
+
+static void timer_interrupt_init(void)
+{
+ irq_handler_register(TIMER0_IRQ_NUM, dw_timer_irq_handler);
+ irq_priority_set(TIMER0_IRQ_NUM);
+ irq_enable(TIMER0_IRQ_NUM);
+ arch_local_irq_enable();
+}
+
+static void timer_interrupt_uninit(void)
+{
+ arch_local_irq_disable();
+ irq_disable(TIMER0_IRQ_NUM);
+}
+
+static int csi_timer_init(void)
+{
+ dw_timer_reset_register();
+ timer_interrupt_init();
+ return 0;
+}
+
+static void csi_timer_uinit(void)
+{
+ timer_interrupt_uninit();
+ dw_timer_reset_register();
+}
+
+int timer_alarm_set(cmd_tbl_t *cmdtp, int flag, int argc,
+ char * const argv[])
+{
+ unsigned long time_us;
+ int ret, state;
+ u32 timeout = 0;
+
+ if (argc != 2) {
+ printf("invalid input parameters\n");
+ return -EINVAL;
+ }
+
+ if (strict_strtoul(argv[1], 10, &time_us) < 0)
+ return CMD_RET_USAGE;
+
+ time_us = time_us * 1000000;
+ ret = csi_timer_init();
+ if(ret) {
+ printf("failed to initialize the timer\n");
+ return -EINVAL;
+ }
+
+ time_user_defined_flag = 0;
+ state = csi_timer_start(time_us);
+ if (state) {
+ printf("failed to start the timer0\n");
+ return ret;
+ }
+
+ do {
+
+ timeout++;
+ //if (!timeout)
+ // break;
+ mdelay(1000);
+ printf("[%s,%d]wait for timer interrupt, %d seconds elapsed\n",
+ __func__, __LINE__, timeout);
+
+ } while (!time_user_defined_flag);
+
+ csi_timer_uinit();
+
+ return 0;
+}
+
+U_BOOT_CMD(timer_alarm, 2, 0, timer_alarm_set, "timer_alarm 10", "timer interrupt test");