source: rtems/bsps/arm/shared/clock/clock-generic-timer.c @ 65870044

Last change on this file since 65870044 was 65870044, checked in by Sebastian Huber <sebastian.huber@…>, on Apr 18, 2019 at 4:47:01 AM

score: Add _SMP_Broadcast_action()

  • Property mode set to 100644
File size: 4.9 KB
Line 
1/*
2 * Copyright (c) 2017 embedded brains GmbH.  All rights reserved.
3 *
4 *  embedded brains GmbH
5 *  Dornierstr. 4
6 *  82178 Puchheim
7 *  Germany
8 *  <info@embedded-brains.de>
9 *
10 * The license and distribution terms for this file may be
11 * found in the file LICENSE in this distribution or at
12 * http://www.rtems.org/license/LICENSE.
13 */
14
15#include <bsp.h>
16#include <bsp/fatal.h>
17#include <bsp/irq.h>
18#include <bsp/irq-generic.h>
19
20#include <rtems/counter.h>
21#include <rtems/sysinit.h>
22#include <rtems/timecounter.h>
23#include <rtems/score/smpimpl.h>
24
25#include <libcpu/arm-cp15.h>
26
27/*
28 * Clock driver using the ARMv7-AR Generic Timer.  The BSP must provide the
29 * following function via <bsp.h>:
30 *
31 * void arm_generic_timer_get_config(uint32_t *frequency, uint32_t *irq);
32 *
33 * The BSP may optionally define ARM_GENERIC_TIMER_USE_VIRTUAL in <bsp.h> to
34 * use the virtual timer instead of the physical timer.
35 */
36
37typedef struct {
38  struct timecounter tc;
39  uint32_t interval;
40  rtems_vector_number irq;
41} arm_gt_clock_context;
42
43static arm_gt_clock_context arm_gt_clock_instance;
44
45/* This is defined in dev/clock/clockimpl.h */
46void Clock_isr(rtems_irq_hdl_param arg);
47
48static inline uint64_t arm_gt_clock_get_compare_value(void)
49{
50#ifdef ARM_GENERIC_TIMER_USE_VIRTUAL
51  return arm_cp15_get_counter_pl1_virtual_compare_value();
52#else
53  return arm_cp15_get_counter_pl1_physical_compare_value();
54#endif
55}
56
57static inline void arm_gt_clock_set_compare_value(uint64_t cval)
58{
59#ifdef ARM_GENERIC_TIMER_USE_VIRTUAL
60  arm_cp15_set_counter_pl1_virtual_compare_value(cval);
61#else
62  arm_cp15_set_counter_pl1_physical_compare_value(cval);
63#endif
64}
65
66static inline uint64_t arm_gt_clock_get_count(void)
67{
68#ifdef ARM_GENERIC_TIMER_USE_VIRTUAL
69  return arm_cp15_get_counter_virtual_count();
70#else
71  return arm_cp15_get_counter_physical_count();
72#endif
73}
74
75static inline void arm_gt_clock_set_control(uint32_t ctl)
76{
77#ifdef ARM_GENERIC_TIMER_USE_VIRTUAL
78  arm_cp15_set_counter_pl1_virtual_timer_control(ctl);
79#else
80  arm_cp15_set_counter_pl1_physical_timer_control(ctl);
81#endif
82}
83
84static void arm_gt_clock_at_tick(void)
85{
86  uint64_t cval;
87  uint32_t interval;
88
89  interval = arm_gt_clock_instance.interval;
90  cval = arm_gt_clock_get_compare_value();
91  cval += interval;
92  arm_gt_clock_set_compare_value(cval);
93}
94
95static void arm_gt_clock_handler_install(void)
96{
97  rtems_status_code sc;
98
99  sc = rtems_interrupt_handler_install(
100    arm_gt_clock_instance.irq,
101    "Clock",
102    RTEMS_INTERRUPT_UNIQUE,
103    (rtems_interrupt_handler) Clock_isr,
104    NULL
105  );
106  if (sc != RTEMS_SUCCESSFUL) {
107    bsp_fatal(BSP_ARM_FATAL_GENERIC_TIMER_CLOCK_IRQ_INSTALL);
108  }
109}
110
111static uint32_t arm_gt_clock_get_timecount(struct timecounter *tc)
112{
113  return (uint32_t) arm_gt_clock_get_count();
114}
115
116static void arm_gt_clock_gt_init(uint64_t cval)
117{
118  arm_gt_clock_set_compare_value(cval);
119  arm_gt_clock_set_control(0x1);
120}
121
122#if defined(RTEMS_SMP) && !defined(CLOCK_DRIVER_USE_ONLY_BOOT_PROCESSOR)
123static void arm_gt_clock_secondary_action(void *arg)
124{
125  if (!_Per_CPU_Is_boot_processor(_Per_CPU_Get())) {
126    uint64_t *cval;
127
128    cval = arg;
129    arm_gt_clock_gt_init(*cval);
130    bsp_interrupt_vector_enable(arm_gt_clock_instance.irq);
131  }
132}
133#endif
134
135static void arm_gt_clock_secondary_initialization(uint64_t cval)
136{
137#if defined(RTEMS_SMP) && !defined(CLOCK_DRIVER_USE_ONLY_BOOT_PROCESSOR)
138  _SMP_Broadcast_action(arm_gt_clock_secondary_action, &cval);
139#endif
140}
141
142static void arm_gt_clock_initialize(void)
143{
144  uint64_t frequency;
145  uint64_t us_per_tick;
146  uint32_t interval;
147  uint64_t cval;
148  struct timecounter *tc;
149
150  frequency = arm_gt_clock_instance.interval;
151  us_per_tick = rtems_configuration_get_microseconds_per_tick();
152  interval = (uint32_t) ((frequency * us_per_tick) / 1000000);
153  cval = arm_gt_clock_get_count();
154  cval += interval;
155  arm_gt_clock_instance.interval = interval;
156
157  arm_gt_clock_gt_init(cval);
158  arm_gt_clock_secondary_initialization(cval);
159
160  tc = &arm_gt_clock_instance.tc;
161  tc->tc_get_timecount = arm_gt_clock_get_timecount;
162  tc->tc_counter_mask = 0xffffffff;
163  tc->tc_frequency = frequency;
164  tc->tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER;
165  rtems_timecounter_install(tc);
166}
167
168uint32_t _CPU_Counter_frequency(void)
169{
170  return (uint32_t) arm_gt_clock_instance.tc.tc_frequency;
171}
172
173CPU_Counter_ticks _CPU_Counter_read(void)
174{
175  return (uint32_t) arm_gt_clock_get_count();
176}
177
178static void arm_gt_clock_early_init(void)
179{
180  arm_gt_clock_set_control(0x3);
181
182  arm_generic_timer_get_config(
183    &arm_gt_clock_instance.interval,
184    &arm_gt_clock_instance.irq
185  );
186}
187
188RTEMS_SYSINIT_ITEM(
189  arm_gt_clock_early_init,
190  RTEMS_SYSINIT_CPU_COUNTER,
191  RTEMS_SYSINIT_ORDER_FIRST
192);
193
194#define Clock_driver_support_at_tick() \
195  arm_gt_clock_at_tick()
196
197#define Clock_driver_support_initialize_hardware() \
198  arm_gt_clock_initialize()
199
200#define Clock_driver_support_install_isr(isr) \
201  arm_gt_clock_handler_install()
202
203/* Include shared source clock driver code */
204#include "../../shared/dev/clock/clockimpl.h"
Note: See TracBrowser for help on using the repository browser.