source: rtems/c/src/lib/libbsp/sparc/shared/timer/tlib_ckinit.c @ 48fed9a

4.115
Last change on this file since 48fed9a was 48fed9a, checked in by Sebastian Huber <sebastian.huber@…>, on 06/25/15 at 12:11:53

score: Simplify <rtems/system.h>

Drop the <rtems/score/percpu.h> include since this file exposes a lot of
implementation details.

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