timer.c 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. /*
  2. * Copyright (C) 2017-2020 Alibaba Group Holding Limited
  3. *
  4. * SPDX-License-Identifier: GPL-2.0+
  5. */
  6. #include <common.h>
  7. #include <asm/io.h>
  8. #include <asm/types.h>
  9. #include <thead/clock_config.h>
  10. #include <linux/bitops.h>
  11. #include <asm/arch-thead/light-iopmp.h>
  12. #include <asm/arch-thead/light-plic.h>
  13. #define DW_TIMER0_BASE 0xffefc32000
  14. #define DW_TIMER0_TLC_REG (DW_TIMER0_BASE + 0x00) /* Offset: 0x000 (R/W) TimerLoadCount */
  15. #define DW_TIMER0_TCV_REG (DW_TIMER0_BASE + 0X04) /* Offset: 0x004 (R/ ) TimerCurrentValue */
  16. #define DW_TIMER0_TCR_REG (DW_TIMER0_BASE + 0X08) /* Offset: 0x008 (R/W) TimerControlReg */
  17. #define DW_TIMER0_TEOI_REG (DW_TIMER0_BASE + 0X0C) /* Offset: 0x00c (R/ ) TimerEOI */
  18. #define DW_TIMER0_TIS_REG (DW_TIMER0_BASE + 0X10) /* Offset: 0x010 (R/ ) TimerIntStatus */
  19. /*! Timer Int Status, offset: 0x10 */
  20. #define DW_TIMER_INT_STATUS_Pos (0U)
  21. #define DW_TIMER_INT_STATUS_Msk (0x1U << DW_TIMER_INT_STATUS_Pos)
  22. #define DW_TIMER_INT_STATUS_EN DW_TIMER_INT_STATUS_Msk
  23. /*! Timer1 Control Reg, offset: 0x08 */
  24. #define DW_TIMER_CTL_ENABLE_SEL_Pos (0U)
  25. #define DW_TIMER_CTL_ENABLE_SEL_Msk (0x1U << DW_TIMER_CTL_ENABLE_SEL_Pos)
  26. #define DW_TIMER_CTL_ENABLE_SEL_EN DW_TIMER_CTL_ENABLE_SEL_Msk
  27. #define DW_TIMER_CTL_MODE_SEL_Pos (1U)
  28. #define DW_TIMER_CTL_MODE_SEL_Msk (0x1U << DW_TIMER_CTL_MODE_SEL_Pos)
  29. #define DW_TIMER_CTL_MODE_SEL_EN DW_TIMER_CTL_MODE_SEL_Msk
  30. #define DW_TIMER_CTL_INT_MASK_Pos (2U)
  31. #define DW_TIMER_CTL_INT_MASK_Msk (0x1U << DW_TIMER_CTL_INT_MASK_Pos)
  32. #define DW_TIMER_CTL_INT_MAKS_EN DW_TIMER_CTL_INT_MASK_Msk
  33. #define DW_TIMER_CTL_HARD_TRIG_Pos (4U)
  34. #define DW_TIMER_CTL_HARD_TRIG_Msk (0x1U << DW_TIMER_CTL_HARD_TRIG_Pos)
  35. #define DW_TIMER_CTL_HARD_TRIG_EN DW_TIMER_CTL_HARD_TRIG_Msk
  36. /*! Timer EOI, offset: 0x0c */
  37. #define DW_TIMER_EOI_REG_Pos (0U)
  38. #define DW_TIMER_EOI_REG_Msk (0x1U << DW_TIMER_EOI_REG_Pos)
  39. #define DW_TIMER_EOI_REG_EN DW_TIMER_EOI_REG_Msk
  40. #define TIMER0_IRQ_NUM 16
  41. #define TIMER0_FREQ_HZ 125000000U
  42. #define DW_TIMER_GET_RELOAD_VAL(_tim_, _frq_) ((_tim_ < 25000U) ? ((_frq_ * _tim_) / 1000U) : (_frq_ * (_tim_ / 1000U)))
  43. static int time_user_defined_flag = 0;
  44. static void csi_timer_stop(void);
  45. static inline u32 dw_timer_get_int_status(void)
  46. {
  47. return (readl((void __iomem *)DW_TIMER0_TIS_REG) & DW_TIMER_INT_STATUS_EN) ? 1 : 0;
  48. }
  49. static inline void dw_timer_clear_irq(void)
  50. {
  51. readl((void __iomem *)DW_TIMER0_TEOI_REG);
  52. }
  53. static inline void dw_timer_write_load(uint32_t value)
  54. {
  55. writel(value, (void __iomem *)DW_TIMER0_TLC_REG);
  56. }
  57. static inline void dw_timer_set_mode_load(void)
  58. {
  59. writel((readl((void __iomem *)DW_TIMER0_TCR_REG) | DW_TIMER_CTL_MODE_SEL_EN), (void __iomem *)DW_TIMER0_TCR_REG);
  60. }
  61. static inline void dw_timer_set_disable(void)
  62. {
  63. u32 data = readl((void __iomem *)DW_TIMER0_TCR_REG);
  64. data &= ~DW_TIMER_CTL_ENABLE_SEL_EN;
  65. writel(data, (void __iomem *)DW_TIMER0_TCR_REG);
  66. }
  67. static inline void dw_timer_set_enable(void)
  68. {
  69. u32 data = readl((void __iomem *)DW_TIMER0_TCR_REG);
  70. data |= DW_TIMER_CTL_ENABLE_SEL_EN;
  71. writel(data, (void __iomem *)DW_TIMER0_TCR_REG);
  72. }
  73. static inline void dw_timer_set_unmask(void)
  74. {
  75. u32 data = readl((void __iomem *)DW_TIMER0_TCR_REG);
  76. data &= ~DW_TIMER_CTL_INT_MAKS_EN;
  77. writel(data, (void __iomem *)DW_TIMER0_TCR_REG);
  78. }
  79. static inline void dw_timer_set_mask(void)
  80. {
  81. u32 data = readl((void __iomem *)DW_TIMER0_TCR_REG);
  82. data |= DW_TIMER_CTL_INT_MAKS_EN;
  83. writel(data, (void __iomem *)DW_TIMER0_TCR_REG);
  84. }
  85. static void dw_timer_irq_handler(void)
  86. {
  87. debug("[%s,%d]\n", __func__, __LINE__);
  88. if (dw_timer_get_int_status()) {
  89. dw_timer_clear_irq();
  90. csi_timer_stop();
  91. debug("[%s,%d]\n", __func__, __LINE__);
  92. time_user_defined_flag = 1;
  93. }
  94. }
  95. static inline void dw_timer_reset_register(void)
  96. {
  97. writel(0, (void __iomem *)DW_TIMER0_TLC_REG);
  98. writel(0, (void __iomem *)DW_TIMER0_TCV_REG);
  99. }
  100. static int csi_timer_start(u32 timeout_us)
  101. {
  102. u32 timer_freq = TIMER0_FREQ_HZ;
  103. u32 tmp_load = DW_TIMER_GET_RELOAD_VAL(timeout_us, timer_freq);
  104. dw_timer_set_mode_load();
  105. //FIXME: no less than 10
  106. if (tmp_load < 10)
  107. tmp_load = 10;
  108. dw_timer_write_load(tmp_load);
  109. dw_timer_set_disable();
  110. dw_timer_set_enable();
  111. dw_timer_set_unmask();
  112. return 0;
  113. }
  114. static void csi_timer_stop(void)
  115. {
  116. dw_timer_set_mask();
  117. dw_timer_set_disable();
  118. }
  119. static void timer_interrupt_init(void)
  120. {
  121. irq_handler_register(TIMER0_IRQ_NUM, dw_timer_irq_handler);
  122. irq_priority_set(TIMER0_IRQ_NUM);
  123. irq_enable(TIMER0_IRQ_NUM);
  124. arch_local_irq_enable();
  125. }
  126. static void timer_interrupt_uninit(void)
  127. {
  128. arch_local_irq_disable();
  129. irq_disable(TIMER0_IRQ_NUM);
  130. }
  131. static int csi_timer_init(void)
  132. {
  133. dw_timer_reset_register();
  134. timer_interrupt_init();
  135. return 0;
  136. }
  137. static void csi_timer_uinit(void)
  138. {
  139. timer_interrupt_uninit();
  140. dw_timer_reset_register();
  141. }
  142. int timer_alarm_set(cmd_tbl_t *cmdtp, int flag, int argc,
  143. char * const argv[])
  144. {
  145. unsigned long time_us;
  146. int ret, state;
  147. u32 timeout = 0;
  148. if (argc != 2) {
  149. printf("invalid input parameters\n");
  150. return -EINVAL;
  151. }
  152. if (strict_strtoul(argv[1], 10, &time_us) < 0)
  153. return CMD_RET_USAGE;
  154. time_us = time_us * 1000000;
  155. ret = csi_timer_init();
  156. if(ret) {
  157. printf("failed to initialize the timer\n");
  158. return -EINVAL;
  159. }
  160. time_user_defined_flag = 0;
  161. state = csi_timer_start(time_us);
  162. if (state) {
  163. printf("failed to start the timer0\n");
  164. return ret;
  165. }
  166. do {
  167. timeout++;
  168. //if (!timeout)
  169. // break;
  170. mdelay(1000);
  171. printf("[%s,%d]wait for timer interrupt, %d seconds elapsed\n",
  172. __func__, __LINE__, timeout);
  173. } while (!time_user_defined_flag);
  174. csi_timer_uinit();
  175. return 0;
  176. }
  177. U_BOOT_CMD(timer_alarm, 2, 0, timer_alarm_set, "timer_alarm 10", "timer interrupt test");