source: rtems/c/src/lib/libbsp/arm/shared/arm-generic-timer-clock-config.c @ c030edd

5
Last change on this file since c030edd was ffe7c0e, checked in by Sebastian Huber <sebastian.huber@…>, on 08/04/17 at 11:56:42

bsps/arm: Add ARMv7-AR Generic Timer clock driver

Update #3090.

  • 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 clockdrv_shell.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_Before_multitasking_action_broadcast(
137    arm_gt_clock_secondary_action,
138    &cval
139  );
140#endif
141}
142
143static void arm_gt_clock_initialize(void)
144{
145  uint64_t frequency;
146  uint64_t us_per_tick;
147  uint32_t interval;
148  uint64_t cval;
149  struct timecounter *tc;
150
151  frequency = arm_gt_clock_instance.interval;
152  us_per_tick = rtems_configuration_get_microseconds_per_tick();
153  interval = (uint32_t) ((frequency * us_per_tick) / 1000000);
154  cval = arm_gt_clock_get_count();
155  cval += interval;
156  arm_gt_clock_instance.interval = interval;
157
158  arm_gt_clock_gt_init(cval);
159  arm_gt_clock_secondary_initialization(cval);
160
161  tc = &arm_gt_clock_instance.tc;
162  tc->tc_get_timecount = arm_gt_clock_get_timecount;
163  tc->tc_counter_mask = 0xffffffff;
164  tc->tc_frequency = frequency;
165  tc->tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER;
166  rtems_timecounter_install(tc);
167}
168
169CPU_Counter_ticks _CPU_Counter_read(void)
170{
171  return (uint32_t) arm_gt_clock_get_count();
172}
173
174static void arm_gt_clock_early_init(void)
175{
176  arm_gt_clock_set_control(0x3);
177
178  arm_generic_timer_get_config(
179    &arm_gt_clock_instance.interval,
180    &arm_gt_clock_instance.irq
181  );
182
183  rtems_counter_initialize_converter(arm_gt_clock_instance.interval);
184}
185
186RTEMS_SYSINIT_ITEM(
187  arm_gt_clock_early_init,
188  RTEMS_SYSINIT_BSP_START,
189  RTEMS_SYSINIT_ORDER_LAST
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, old_isr) \
199  do { \
200    arm_gt_clock_handler_install(); \
201    old_isr = NULL; \
202  } while (0)
203
204/* Include shared source clock driver code */
205#include "../../shared/clockdrv_shell.h"
Note: See TracBrowser for help on using the repository browser.