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

Last change on this file since 7fdf48a was 7fdf48a, checked in by Sebastian Huber <sebastian.huber@…>, on Apr 28, 2019 at 12:29:21 PM

score: Add _SMP_Othercast_action()

  • Property mode set to 100644
File size: 4.8 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  uint64_t *cval;
126
127  cval = arg;
128  arm_gt_clock_gt_init(*cval);
129  bsp_interrupt_vector_enable(arm_gt_clock_instance.irq);
130}
131#endif
132
133static void arm_gt_clock_secondary_initialization(uint64_t cval)
134{
135#if defined(RTEMS_SMP) && !defined(CLOCK_DRIVER_USE_ONLY_BOOT_PROCESSOR)
136  _SMP_Broadcast_action(arm_gt_clock_secondary_action, &cval);
137#endif
138}
139
140static void arm_gt_clock_initialize(void)
141{
142  uint64_t frequency;
143  uint64_t us_per_tick;
144  uint32_t interval;
145  uint64_t cval;
146  struct timecounter *tc;
147
148  frequency = arm_gt_clock_instance.interval;
149  us_per_tick = rtems_configuration_get_microseconds_per_tick();
150  interval = (uint32_t) ((frequency * us_per_tick) / 1000000);
151  cval = arm_gt_clock_get_count();
152  cval += interval;
153  arm_gt_clock_instance.interval = interval;
154
155  arm_gt_clock_gt_init(cval);
156  arm_gt_clock_secondary_initialization(cval);
157
158  tc = &arm_gt_clock_instance.tc;
159  tc->tc_get_timecount = arm_gt_clock_get_timecount;
160  tc->tc_counter_mask = 0xffffffff;
161  tc->tc_frequency = frequency;
162  tc->tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER;
163  rtems_timecounter_install(tc);
164}
165
166uint32_t _CPU_Counter_frequency(void)
167{
168  return (uint32_t) arm_gt_clock_instance.tc.tc_frequency;
169}
170
171CPU_Counter_ticks _CPU_Counter_read(void)
172{
173  return (uint32_t) arm_gt_clock_get_count();
174}
175
176static void arm_gt_clock_early_init(void)
177{
178  arm_gt_clock_set_control(0x3);
179
180  arm_generic_timer_get_config(
181    &arm_gt_clock_instance.interval,
182    &arm_gt_clock_instance.irq
183  );
184}
185
186RTEMS_SYSINIT_ITEM(
187  arm_gt_clock_early_init,
188  RTEMS_SYSINIT_CPU_COUNTER,
189  RTEMS_SYSINIT_ORDER_FIRST
190);
191
192#define Clock_driver_support_at_tick() \
193  arm_gt_clock_at_tick()
194
195#define Clock_driver_support_initialize_hardware() \
196  arm_gt_clock_initialize()
197
198#define Clock_driver_support_install_isr(isr) \
199  arm_gt_clock_handler_install()
200
201/* Include shared source clock driver code */
202#include "../../shared/dev/clock/clockimpl.h"
Note: See TracBrowser for help on using the repository browser.