timer-sun4i.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Allwinner A1X SoCs timer handling.
  4. *
  5. * Copyright (C) 2012 Maxime Ripard
  6. *
  7. * Maxime Ripard <[email protected]>
  8. *
  9. * Based on code from
  10. * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
  11. * Benn Huang <[email protected]>
  12. */
  13. #include <linux/clk.h>
  14. #include <linux/clockchips.h>
  15. #include <linux/interrupt.h>
  16. #include <linux/irq.h>
  17. #include <linux/irqreturn.h>
  18. #include <linux/sched_clock.h>
  19. #include <linux/of.h>
  20. #include <linux/of_address.h>
  21. #include <linux/of_irq.h>
  22. #include "timer-of.h"
  23. #define TIMER_IRQ_EN_REG 0x00
  24. #define TIMER_IRQ_EN(val) BIT(val)
  25. #define TIMER_IRQ_ST_REG 0x04
  26. #define TIMER_IRQ_CLEAR(val) BIT(val)
  27. #define TIMER_CTL_REG(val) (0x10 * val + 0x10)
  28. #define TIMER_CTL_ENABLE BIT(0)
  29. #define TIMER_CTL_RELOAD BIT(1)
  30. #define TIMER_CTL_CLK_SRC(val) (((val) & 0x3) << 2)
  31. #define TIMER_CTL_CLK_SRC_OSC24M (1)
  32. #define TIMER_CTL_CLK_PRES(val) (((val) & 0x7) << 4)
  33. #define TIMER_CTL_ONESHOT BIT(7)
  34. #define TIMER_INTVAL_REG(val) (0x10 * (val) + 0x14)
  35. #define TIMER_CNTVAL_REG(val) (0x10 * (val) + 0x18)
  36. #define TIMER_SYNC_TICKS 3
  37. /*
  38. * When we disable a timer, we need to wait at least for 2 cycles of
  39. * the timer source clock. We will use for that the clocksource timer
  40. * that is already setup and runs at the same frequency than the other
  41. * timers, and we never will be disabled.
  42. */
  43. static void sun4i_clkevt_sync(void __iomem *base)
  44. {
  45. u32 old = readl(base + TIMER_CNTVAL_REG(1));
  46. while ((old - readl(base + TIMER_CNTVAL_REG(1))) < TIMER_SYNC_TICKS)
  47. cpu_relax();
  48. }
  49. static void sun4i_clkevt_time_stop(void __iomem *base, u8 timer)
  50. {
  51. u32 val = readl(base + TIMER_CTL_REG(timer));
  52. writel(val & ~TIMER_CTL_ENABLE, base + TIMER_CTL_REG(timer));
  53. sun4i_clkevt_sync(base);
  54. }
  55. static void sun4i_clkevt_time_setup(void __iomem *base, u8 timer,
  56. unsigned long delay)
  57. {
  58. writel(delay, base + TIMER_INTVAL_REG(timer));
  59. }
  60. static void sun4i_clkevt_time_start(void __iomem *base, u8 timer,
  61. bool periodic)
  62. {
  63. u32 val = readl(base + TIMER_CTL_REG(timer));
  64. if (periodic)
  65. val &= ~TIMER_CTL_ONESHOT;
  66. else
  67. val |= TIMER_CTL_ONESHOT;
  68. writel(val | TIMER_CTL_ENABLE | TIMER_CTL_RELOAD,
  69. base + TIMER_CTL_REG(timer));
  70. }
  71. static int sun4i_clkevt_shutdown(struct clock_event_device *evt)
  72. {
  73. struct timer_of *to = to_timer_of(evt);
  74. sun4i_clkevt_time_stop(timer_of_base(to), 0);
  75. return 0;
  76. }
  77. static int sun4i_clkevt_set_oneshot(struct clock_event_device *evt)
  78. {
  79. struct timer_of *to = to_timer_of(evt);
  80. sun4i_clkevt_time_stop(timer_of_base(to), 0);
  81. sun4i_clkevt_time_start(timer_of_base(to), 0, false);
  82. return 0;
  83. }
  84. static int sun4i_clkevt_set_periodic(struct clock_event_device *evt)
  85. {
  86. struct timer_of *to = to_timer_of(evt);
  87. sun4i_clkevt_time_stop(timer_of_base(to), 0);
  88. sun4i_clkevt_time_setup(timer_of_base(to), 0, timer_of_period(to));
  89. sun4i_clkevt_time_start(timer_of_base(to), 0, true);
  90. return 0;
  91. }
  92. static int sun4i_clkevt_next_event(unsigned long evt,
  93. struct clock_event_device *clkevt)
  94. {
  95. struct timer_of *to = to_timer_of(clkevt);
  96. sun4i_clkevt_time_stop(timer_of_base(to), 0);
  97. sun4i_clkevt_time_setup(timer_of_base(to), 0, evt - TIMER_SYNC_TICKS);
  98. sun4i_clkevt_time_start(timer_of_base(to), 0, false);
  99. return 0;
  100. }
  101. static void sun4i_timer_clear_interrupt(void __iomem *base)
  102. {
  103. writel(TIMER_IRQ_CLEAR(0), base + TIMER_IRQ_ST_REG);
  104. }
  105. static irqreturn_t sun4i_timer_interrupt(int irq, void *dev_id)
  106. {
  107. struct clock_event_device *evt = dev_id;
  108. struct timer_of *to = to_timer_of(evt);
  109. sun4i_timer_clear_interrupt(timer_of_base(to));
  110. evt->event_handler(evt);
  111. return IRQ_HANDLED;
  112. }
  113. static struct timer_of to = {
  114. .flags = TIMER_OF_IRQ | TIMER_OF_CLOCK | TIMER_OF_BASE,
  115. .clkevt = {
  116. .name = "sun4i_tick",
  117. .rating = 350,
  118. .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
  119. .set_state_shutdown = sun4i_clkevt_shutdown,
  120. .set_state_periodic = sun4i_clkevt_set_periodic,
  121. .set_state_oneshot = sun4i_clkevt_set_oneshot,
  122. .tick_resume = sun4i_clkevt_shutdown,
  123. .set_next_event = sun4i_clkevt_next_event,
  124. .cpumask = cpu_possible_mask,
  125. },
  126. .of_irq = {
  127. .handler = sun4i_timer_interrupt,
  128. .flags = IRQF_TIMER | IRQF_IRQPOLL,
  129. },
  130. };
  131. static u64 notrace sun4i_timer_sched_read(void)
  132. {
  133. return ~readl(timer_of_base(&to) + TIMER_CNTVAL_REG(1));
  134. }
  135. static int __init sun4i_timer_init(struct device_node *node)
  136. {
  137. int ret;
  138. u32 val;
  139. ret = timer_of_init(node, &to);
  140. if (ret)
  141. return ret;
  142. writel(~0, timer_of_base(&to) + TIMER_INTVAL_REG(1));
  143. writel(TIMER_CTL_ENABLE | TIMER_CTL_RELOAD |
  144. TIMER_CTL_CLK_SRC(TIMER_CTL_CLK_SRC_OSC24M),
  145. timer_of_base(&to) + TIMER_CTL_REG(1));
  146. /*
  147. * sched_clock_register does not have priorities, and on sun6i and
  148. * later there is a better sched_clock registered by arm_arch_timer.c
  149. */
  150. if (of_machine_is_compatible("allwinner,sun4i-a10") ||
  151. of_machine_is_compatible("allwinner,sun5i-a13") ||
  152. of_machine_is_compatible("allwinner,sun5i-a10s") ||
  153. of_machine_is_compatible("allwinner,suniv-f1c100s"))
  154. sched_clock_register(sun4i_timer_sched_read, 32,
  155. timer_of_rate(&to));
  156. ret = clocksource_mmio_init(timer_of_base(&to) + TIMER_CNTVAL_REG(1),
  157. node->name, timer_of_rate(&to), 350, 32,
  158. clocksource_mmio_readl_down);
  159. if (ret) {
  160. pr_err("Failed to register clocksource\n");
  161. return ret;
  162. }
  163. writel(TIMER_CTL_CLK_SRC(TIMER_CTL_CLK_SRC_OSC24M),
  164. timer_of_base(&to) + TIMER_CTL_REG(0));
  165. /* Make sure timer is stopped before playing with interrupts */
  166. sun4i_clkevt_time_stop(timer_of_base(&to), 0);
  167. /* clear timer0 interrupt */
  168. sun4i_timer_clear_interrupt(timer_of_base(&to));
  169. clockevents_config_and_register(&to.clkevt, timer_of_rate(&to),
  170. TIMER_SYNC_TICKS, 0xffffffff);
  171. /* Enable timer0 interrupt */
  172. val = readl(timer_of_base(&to) + TIMER_IRQ_EN_REG);
  173. writel(val | TIMER_IRQ_EN(0), timer_of_base(&to) + TIMER_IRQ_EN_REG);
  174. return ret;
  175. }
  176. TIMER_OF_DECLARE(sun4i, "allwinner,sun4i-a10-timer",
  177. sun4i_timer_init);
  178. TIMER_OF_DECLARE(sun8i_a23, "allwinner,sun8i-a23-timer",
  179. sun4i_timer_init);
  180. TIMER_OF_DECLARE(sun8i_v3s, "allwinner,sun8i-v3s-timer",
  181. sun4i_timer_init);
  182. TIMER_OF_DECLARE(suniv, "allwinner,suniv-f1c100s-timer",
  183. sun4i_timer_init);