source: rtems/c/src/lib/libbsp/sparc/shared/timer/tlib_ckinit.c @ 30f8412

4.115
Last change on this file since 30f8412 was 30f8412, checked in by Sebastian Huber <sebastian.huber@…>, on 06/09/15 at 05:45:51

bsps/sparc: tlib clock driver timecounter support

  • Property mode set to 100644
File size: 5.8 KB
Line 
1/*
2 *  Clock Tick Device Driver using Timer Library implemented
3 *  by the GRLIB GPTIMER / LEON2 Timer drivers.
4 *
5 *  COPYRIGHT (c) 2010.
6 *  Cobham Gaisler AB.
7 *
8 *  The license and distribution terms for this file may be
9 *  found in the file LICENSE in this distribution or at
10 *  http://www.rtems.org/license/LICENSE.
11 *
12 */
13
14#include <rtems.h>
15#include <rtems/timecounter.h>
16#include <stdlib.h>
17#include <bsp.h>
18#include <bsp/tlib.h>
19
20#ifdef RTEMS_DRVMGR_STARTUP
21
22/* Undefine this to save space in standard LEON configurations,
23 * it will assume that Prescaler is running at 1MHz.
24 */
25#undef CLOCK_DRIVER_DONT_ASSUME_PRESCALER_1MHZ
26
27/* Set the below defines from bsp.h if function needed.
28#undef CLOCK_DRIVER_ISRS_PER_TICK
29#undef CLOCK_DRIVER_USE_FAST_IDLE
30*/
31#define Clock_driver_support_at_tick()
32
33/*
34 *  Number of Clock ticks since initialization
35 */
36volatile uint32_t Clock_driver_ticks;
37
38/*
39 *  Timer Number in Timer Library. Defaults to the first Timer in
40 *  the System.
41 */
42int Clock_timer = 0;
43
44/*
45 * Timer Handle in Timer Library
46 */
47void *Clock_handle = NULL;
48
49#ifdef CLOCK_DRIVER_DONT_ASSUME_PRESCALER_1MHZ
50unsigned int Clock_basefreq;
51#endif
52
53void Clock_exit(void);
54void Clock_isr(void *arg_unused);
55
56static rtems_timecounter_simple tlib_tc;
57
58static uint32_t tlib_tc_get(rtems_timecounter_simple *tc)
59{
60  unsigned int clicks = 0;
61
62  if (Clock_handle != NULL) {
63    tlib_get_counter(Clock_handle, &clicks);
64  }
65
66  return clicks;
67}
68
69static bool tlib_tc_is_pending(rtems_timecounter_simple *tc)
70{
71  bool pending = false;
72
73  if (Clock_handle != NULL) {
74    pending = tlib_interrupt_pending(Clock_handle, 0) != 0;
75  }
76
77  return pending;
78}
79
80static uint32_t tlib_tc_get_timecount(struct timecounter *tc)
81{
82  return rtems_timecounter_simple_downcounter_get(
83    tc,
84    tlib_tc_get,
85    tlib_tc_is_pending
86  );
87}
88
89static void tlib_tc_tick(void)
90{
91  rtems_timecounter_simple_downcounter_tick(
92    &tlib_tc,
93    tlib_tc_get
94  );
95}
96
97/*
98 *  Clock_isr
99 *
100 *  This is the clock tick interrupt handler.
101 *
102 *  Input parameters:
103 *    vector - vector number
104 *
105 *  Output parameters:  NONE
106 *
107 *  Return values:      NONE
108 *
109 */
110
111void Clock_isr(void *arg_unused)
112{
113  /*
114   * Support for shared interrupts. Ack IRQ at source, only handle
115   * interrupts generated from the tick-timer.
116   */
117  if ( tlib_interrupt_pending(Clock_handle, 1) == 0 )
118    return;
119
120  /*
121   *  Accurate count of ISRs
122   */
123
124  Clock_driver_ticks += 1;
125
126#ifdef CLOCK_DRIVER_USE_FAST_IDLE
127  do {
128    tlib_tc_tick();
129  } while ( _Thread_Executing == _Thread_Idle &&
130          _Thread_Heir == _Thread_Executing);
131
132  Clock_driver_support_at_tick();
133  return;
134
135#else
136
137  /*
138   * Add custom handling at every tick from bsp.h
139   */
140  Clock_driver_support_at_tick();
141
142#ifdef CLOCK_DRIVER_ISRS_PER_TICK
143  /*
144   *  The driver is multiple ISRs per clock tick.
145   */
146
147  if ( !Clock_driver_isrs ) {
148
149    tlib_tc_tick();
150
151    Clock_driver_isrs = CLOCK_DRIVER_ISRS_PER_TICK;
152  }
153  Clock_driver_isrs--;
154#else
155
156  /*
157   *  The driver is one ISR per clock tick.
158   */
159  tlib_tc_tick();
160#endif
161#endif
162}
163
164/*
165 *  Clock_exit
166 *
167 *  This routine allows the clock driver to exit by masking the interrupt and
168 *  disabling the clock's counter.
169 *
170 *  Input parameters:   NONE
171 *
172 *  Output parameters:  NONE
173 *
174 *  Return values:      NONE
175 *
176 */
177
178void Clock_exit( void )
179{
180  /* Stop all activity of the Timer, no more ISRs.
181   * We could be using tlib_close(), however tlib_stop() is quicker
182   * and independent of IRQ unregister code.
183   */
184  if ( Clock_handle ) {
185    tlib_stop(Clock_handle);
186    Clock_handle = NULL;
187  }
188}
189
190/*
191 *  Clock_initialize
192 *
193 *  This routine initializes the clock driver and starts the Clock.
194 *
195 *  Input parameters:
196 *    major - clock device major number
197 *    minor - clock device minor number
198 *    parg  - pointer to optional device driver arguments
199 *
200 *  Output parameters:  NONE
201 *
202 *  Return values:
203 *    rtems_device_driver status code
204 */
205
206rtems_device_driver Clock_initialize(
207  rtems_device_major_number major,
208  rtems_device_minor_number minor,
209  void *pargp
210)
211{
212  uint64_t frequency;
213  unsigned int tick_hz;
214
215  /*
216   *  Take Timer that should be used as system timer.
217   *
218   */
219  Clock_handle = tlib_open(Clock_timer);
220  if ( Clock_handle == NULL ) {
221    /* System Clock Timer not found */
222    return RTEMS_NOT_DEFINED;
223  }
224
225  /*
226   *  Install Clock ISR before starting timer
227   */
228  tlib_irq_register(Clock_handle, Clock_isr, NULL);
229
230  /* Set Timer Frequency to tick at Configured value. The Timer
231   * Frequency is set in multiples of the timer base frequency.
232   *
233   * In standard LEON3 designs the base frequency is is 1MHz, to
234   * save instructions undefine CLOCK_DRIVER_DONT_ASSUME_PRESCALER_1MHZ
235   * to avoid 64-bit calculation.
236   */
237#ifdef CLOCK_DRIVER_DONT_ASSUME_PRESCALER_1MHZ
238  {
239    uint64_t tmp;
240
241    tlib_get_freq(Clock_handle, &Clock_basefreq, NULL);
242
243    frequency = Clock_basefreq
244    tmp = frequency * (uint64_t)rtems_configuration_get_microseconds_per_tick();
245    tick_hz = tmp / 1000000;
246  }
247#else
248  frequency = 1000000;
249  tick_hz = rtems_configuration_get_microseconds_per_tick();
250#endif
251
252  tlib_set_freq(Clock_handle, tick_hz);
253
254  rtems_timecounter_simple_install(
255    &tlib_tc,
256    frequency,
257    tick_hz,
258    tlib_tc_get_timecount
259  );
260
261  /*
262   *  IRQ and Frequency is setup, now we start the Timer. IRQ is still
263   *  disabled globally during startup, so IRQ will hold for a while.
264   */
265  tlib_start(Clock_handle, 0);
266
267  /*
268   *  Register function called at system shutdown
269   */
270  atexit( Clock_exit );
271
272  /*
273   *  If we are counting ISRs per tick, then initialize the counter.
274   */
275
276#ifdef CLOCK_DRIVER_ISRS_PER_TICK
277  Clock_driver_isrs = CLOCK_DRIVER_ISRS_PER_TICK;
278#endif
279
280  return RTEMS_SUCCESSFUL;
281}
282
283/*** Timer Driver Interface ***/
284
285/* Set system clock timer instance */
286void Clock_timer_register(int timer_number)
287{
288  Clock_timer = timer_number;
289}
290
291#endif
Note: See TracBrowser for help on using the repository browser.