timer-sun4i.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  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 <maxime.ripard@free-electrons.com>
  8. *
  9. * Based on code from
  10. * Allwinner Technology Co., Ltd. <www.allwinnertech.com>
  11. * Benn Huang <benn@allwinnertech.com>
  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. CLOCK_EVT_FEAT_DYNIRQ,
  120. .set_state_shutdown = sun4i_clkevt_shutdown,
  121. .set_state_periodic = sun4i_clkevt_set_periodic,
  122. .set_state_oneshot = sun4i_clkevt_set_oneshot,
  123. .tick_resume = sun4i_clkevt_shutdown,
  124. .set_next_event = sun4i_clkevt_next_event,
  125. .cpumask = cpu_possible_mask,
  126. },
  127. .of_irq = {
  128. .handler = sun4i_timer_interrupt,
  129. .flags = IRQF_TIMER | IRQF_IRQPOLL,
  130. },
  131. };
  132. static u64 notrace sun4i_timer_sched_read(void)
  133. {
  134. return ~readl(timer_of_base(&to) + TIMER_CNTVAL_REG(1));
  135. }
  136. static int __init sun4i_timer_init(struct device_node *node)
  137. {
  138. int ret;
  139. u32 val;
  140. ret = timer_of_init(node, &to);
  141. if (ret)
  142. return ret;
  143. writel(~0, timer_of_base(&to) + TIMER_INTVAL_REG(1));
  144. writel(TIMER_CTL_ENABLE | TIMER_CTL_RELOAD |
  145. TIMER_CTL_CLK_SRC(TIMER_CTL_CLK_SRC_OSC24M),
  146. timer_of_base(&to) + TIMER_CTL_REG(1));
  147. /*
  148. * sched_clock_register does not have priorities, and on sun6i and
  149. * later there is a better sched_clock registered by arm_arch_timer.c
  150. */
  151. if (of_machine_is_compatible("allwinner,sun4i-a10") ||
  152. of_machine_is_compatible("allwinner,sun5i-a13") ||
  153. of_machine_is_compatible("allwinner,sun5i-a10s") ||
  154. of_machine_is_compatible("allwinner,suniv-f1c100s"))
  155. sched_clock_register(sun4i_timer_sched_read, 32,
  156. timer_of_rate(&to));
  157. ret = clocksource_mmio_init(timer_of_base(&to) + TIMER_CNTVAL_REG(1),
  158. node->name, timer_of_rate(&to), 350, 32,
  159. clocksource_mmio_readl_down);
  160. if (ret) {
  161. pr_err("Failed to register clocksource\n");
  162. return ret;
  163. }
  164. writel(TIMER_CTL_CLK_SRC(TIMER_CTL_CLK_SRC_OSC24M),
  165. timer_of_base(&to) + TIMER_CTL_REG(0));
  166. /* Make sure timer is stopped before playing with interrupts */
  167. sun4i_clkevt_time_stop(timer_of_base(&to), 0);
  168. /* clear timer0 interrupt */
  169. sun4i_timer_clear_interrupt(timer_of_base(&to));
  170. clockevents_config_and_register(&to.clkevt, timer_of_rate(&to),
  171. TIMER_SYNC_TICKS, 0xffffffff);
  172. /* Enable timer0 interrupt */
  173. val = readl(timer_of_base(&to) + TIMER_IRQ_EN_REG);
  174. writel(val | TIMER_IRQ_EN(0), timer_of_base(&to) + TIMER_IRQ_EN_REG);
  175. return ret;
  176. }
  177. TIMER_OF_DECLARE(sun4i, "allwinner,sun4i-a10-timer",
  178. sun4i_timer_init);
  179. TIMER_OF_DECLARE(sun8i_a23, "allwinner,sun8i-a23-timer",
  180. sun4i_timer_init);
  181. TIMER_OF_DECLARE(sun8i_v3s, "allwinner,sun8i-v3s-timer",
  182. sun4i_timer_init);
  183. TIMER_OF_DECLARE(suniv, "allwinner,suniv-f1c100s-timer",
  184. sun4i_timer_init);