source: rtems/c/src/lib/libbsp/sparc/shared/timer/tlib_ckinit.c @ 4a7d1026

4.115
Last change on this file since 4a7d1026 was 4a7d1026, checked in by Daniel Hellstrom <daniel@…>, on 04/13/15 at 08:25:52

sparc bsps: updated license to rtems.org

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