timer-integrator-ap.c 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * Integrator/AP timer driver
  4. * Copyright (C) 2000-2003 Deep Blue Solutions Ltd
  5. * Copyright (c) 2014, Linaro Limited
  6. */
  7. #include <linux/clk.h>
  8. #include <linux/clocksource.h>
  9. #include <linux/of_irq.h>
  10. #include <linux/of_address.h>
  11. #include <linux/of_platform.h>
  12. #include <linux/clockchips.h>
  13. #include <linux/interrupt.h>
  14. #include <linux/sched_clock.h>
  15. #include "timer-sp.h"
  16. static void __iomem * sched_clk_base;
  17. static u64 notrace integrator_read_sched_clock(void)
  18. {
  19. return -readl(sched_clk_base + TIMER_VALUE);
  20. }
  21. static int __init integrator_clocksource_init(unsigned long inrate,
  22. void __iomem *base)
  23. {
  24. u32 ctrl = TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC;
  25. unsigned long rate = inrate;
  26. int ret;
  27. if (rate >= 1500000) {
  28. rate /= 16;
  29. ctrl |= TIMER_CTRL_DIV16;
  30. }
  31. writel(0xffff, base + TIMER_LOAD);
  32. writel(ctrl, base + TIMER_CTRL);
  33. ret = clocksource_mmio_init(base + TIMER_VALUE, "timer2",
  34. rate, 200, 16, clocksource_mmio_readl_down);
  35. if (ret)
  36. return ret;
  37. sched_clk_base = base;
  38. sched_clock_register(integrator_read_sched_clock, 16, rate);
  39. return 0;
  40. }
  41. static unsigned long timer_reload;
  42. static void __iomem * clkevt_base;
  43. /*
  44. * IRQ handler for the timer
  45. */
  46. static irqreturn_t integrator_timer_interrupt(int irq, void *dev_id)
  47. {
  48. struct clock_event_device *evt = dev_id;
  49. /* clear the interrupt */
  50. writel(1, clkevt_base + TIMER_INTCLR);
  51. evt->event_handler(evt);
  52. return IRQ_HANDLED;
  53. }
  54. static int clkevt_shutdown(struct clock_event_device *evt)
  55. {
  56. u32 ctrl = readl(clkevt_base + TIMER_CTRL) & ~TIMER_CTRL_ENABLE;
  57. /* Disable timer */
  58. writel(ctrl, clkevt_base + TIMER_CTRL);
  59. return 0;
  60. }
  61. static int clkevt_set_oneshot(struct clock_event_device *evt)
  62. {
  63. u32 ctrl = readl(clkevt_base + TIMER_CTRL) &
  64. ~(TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC);
  65. /* Leave the timer disabled, .set_next_event will enable it */
  66. writel(ctrl, clkevt_base + TIMER_CTRL);
  67. return 0;
  68. }
  69. static int clkevt_set_periodic(struct clock_event_device *evt)
  70. {
  71. u32 ctrl = readl(clkevt_base + TIMER_CTRL) & ~TIMER_CTRL_ENABLE;
  72. /* Disable timer */
  73. writel(ctrl, clkevt_base + TIMER_CTRL);
  74. /* Enable the timer and start the periodic tick */
  75. writel(timer_reload, clkevt_base + TIMER_LOAD);
  76. ctrl |= TIMER_CTRL_PERIODIC | TIMER_CTRL_ENABLE;
  77. writel(ctrl, clkevt_base + TIMER_CTRL);
  78. return 0;
  79. }
  80. static int clkevt_set_next_event(unsigned long next, struct clock_event_device *evt)
  81. {
  82. unsigned long ctrl = readl(clkevt_base + TIMER_CTRL);
  83. writel(ctrl & ~TIMER_CTRL_ENABLE, clkevt_base + TIMER_CTRL);
  84. writel(next, clkevt_base + TIMER_LOAD);
  85. writel(ctrl | TIMER_CTRL_ENABLE, clkevt_base + TIMER_CTRL);
  86. return 0;
  87. }
  88. static struct clock_event_device integrator_clockevent = {
  89. .name = "timer1",
  90. .features = CLOCK_EVT_FEAT_PERIODIC |
  91. CLOCK_EVT_FEAT_ONESHOT,
  92. .set_state_shutdown = clkevt_shutdown,
  93. .set_state_periodic = clkevt_set_periodic,
  94. .set_state_oneshot = clkevt_set_oneshot,
  95. .tick_resume = clkevt_shutdown,
  96. .set_next_event = clkevt_set_next_event,
  97. .rating = 300,
  98. };
  99. static int integrator_clockevent_init(unsigned long inrate,
  100. void __iomem *base, int irq)
  101. {
  102. unsigned long rate = inrate;
  103. unsigned int ctrl = 0;
  104. int ret;
  105. clkevt_base = base;
  106. /* Calculate and program a divisor */
  107. if (rate > 0x100000 * HZ) {
  108. rate /= 256;
  109. ctrl |= TIMER_CTRL_DIV256;
  110. } else if (rate > 0x10000 * HZ) {
  111. rate /= 16;
  112. ctrl |= TIMER_CTRL_DIV16;
  113. }
  114. timer_reload = rate / HZ;
  115. writel(ctrl, clkevt_base + TIMER_CTRL);
  116. ret = request_irq(irq, integrator_timer_interrupt,
  117. IRQF_TIMER | IRQF_IRQPOLL, "timer",
  118. &integrator_clockevent);
  119. if (ret)
  120. return ret;
  121. clockevents_config_and_register(&integrator_clockevent,
  122. rate,
  123. 1,
  124. 0xffffU);
  125. return 0;
  126. }
  127. static int __init integrator_ap_timer_init_of(struct device_node *node)
  128. {
  129. const char *path;
  130. void __iomem *base;
  131. int err;
  132. int irq;
  133. struct clk *clk;
  134. unsigned long rate;
  135. struct device_node *alias_node;
  136. base = of_io_request_and_map(node, 0, "integrator-timer");
  137. if (IS_ERR(base))
  138. return PTR_ERR(base);
  139. clk = of_clk_get(node, 0);
  140. if (IS_ERR(clk)) {
  141. pr_err("No clock for %pOFn\n", node);
  142. return PTR_ERR(clk);
  143. }
  144. clk_prepare_enable(clk);
  145. rate = clk_get_rate(clk);
  146. writel(0, base + TIMER_CTRL);
  147. err = of_property_read_string(of_aliases,
  148. "arm,timer-primary", &path);
  149. if (err) {
  150. pr_warn("Failed to read property\n");
  151. return err;
  152. }
  153. alias_node = of_find_node_by_path(path);
  154. /*
  155. * The pointer is used as an identifier not as a pointer, we
  156. * can drop the refcount on the of__node immediately after
  157. * getting it.
  158. */
  159. of_node_put(alias_node);
  160. if (node == alias_node)
  161. /* The primary timer lacks IRQ, use as clocksource */
  162. return integrator_clocksource_init(rate, base);
  163. err = of_property_read_string(of_aliases,
  164. "arm,timer-secondary", &path);
  165. if (err) {
  166. pr_warn("Failed to read property\n");
  167. return err;
  168. }
  169. alias_node = of_find_node_by_path(path);
  170. of_node_put(alias_node);
  171. if (node == alias_node) {
  172. /* The secondary timer will drive the clock event */
  173. irq = irq_of_parse_and_map(node, 0);
  174. return integrator_clockevent_init(rate, base, irq);
  175. }
  176. pr_info("Timer @%p unused\n", base);
  177. clk_disable_unprepare(clk);
  178. return 0;
  179. }
  180. TIMER_OF_DECLARE(integrator_ap_timer, "arm,integrator-timer",
  181. integrator_ap_timer_init_of);