source: rtems/c/src/lib/libcpu/powerpc/mpc6xx/clock/c_clock.c @ 9c325fb2

4.104.114.9
Last change on this file since 9c325fb2 was 9c325fb2, checked in by Joel Sherrill <joel.sherrill@…>, on Jul 16, 2008 at 8:22:20 PM

2008-07-16 Joel Sherrill <joel.sherrill@…>

  • mpc6xx/clock/c_clock.c: Add fast idle.
  • Property mode set to 100644
File size: 7.3 KB
Line 
1/*
2 *  Clock Tick Device Driver
3 *
4 *  This routine utilizes the Decrementer Register common to the PPC family.
5 *
6 *  The tick frequency is directly programmed to the configured number of
7 *  microseconds per tick.
8 *
9 *  COPYRIGHT (c) 1989-2007.
10 *  On-Line Applications Research Corporation (OAR).
11 *
12 *  The license and distribution terms for this file may in
13 *  the file LICENSE in this distribution or at
14 *  http://www.rtems.com/license/LICENSE.
15 *
16 *  Modified to support the MPC750.
17 *  Modifications Copyright (c) 1999 Eric Valette valette@crf.canon.fr
18 *
19 *  $Id$
20 */
21
22#include <rtems/system.h>
23#include <rtems.h>
24#include <rtems/libio.h>
25#include <stdlib.h>                     /* for atexit() */
26#include <assert.h>
27#include <libcpu/c_clock.h>
28#include <libcpu/cpuIdent.h>
29#include <libcpu/spr.h>
30#include <rtems/bspIo.h>                /* for printk() */
31
32#include <bspopts.h>   /* for CLOCK_DRIVER_USE_FAST_IDLE */
33
34SPR_RW(BOOKE_TCR)
35SPR_RW(BOOKE_TSR)
36SPR_RW(BOOKE_DECAR)
37SPR_RW(DEC)
38
39extern int BSP_connect_clock_handler (void);
40
41/*
42 *  Clock ticks since initialization
43 */
44
45volatile uint32_t   Clock_driver_ticks;
46
47/*
48 *  This is the value programmed into the count down timer.
49 */
50
51uint32_t   Clock_Decrementer_value;
52
53/*
54 * These are set by clock driver during its init
55 */
56 
57rtems_device_major_number rtems_clock_major = ~0;
58rtems_device_minor_number rtems_clock_minor;
59
60void clockOff(void* unused)
61{
62rtems_interrupt_level l;
63
64  if ( ppc_cpu_is_bookE() ) {
65    rtems_interrupt_disable(l);
66    _write_BOOKE_TCR(_read_BOOKE_TCR() & ~BOOKE_TCR_DIE);
67    rtems_interrupt_enable(l);
68  } else {
69  /*
70   * Nothing to do as we cannot disable all interrupts and
71   * the decrementer interrupt enable is MSR_EE
72   */
73  }
74}
75
76void clockOn(void* unused)
77{
78rtems_interrupt_level l;
79
80  PPC_Set_decrementer( Clock_Decrementer_value );
81
82  if ( ppc_cpu_is_bookE() ) {
83    _write_BOOKE_DECAR( Clock_Decrementer_value );
84
85    rtems_interrupt_disable(l);
86
87    /* clear pending/stale irq */
88    _write_BOOKE_TSR( BOOKE_TSR_DIS );
89    /* enable */
90    _write_BOOKE_TCR( _read_BOOKE_TCR() | BOOKE_TCR_DIE );
91
92    rtems_interrupt_enable(l);
93
94  }
95}
96
97static void clockHandler(void)
98{
99
100  #if defined(CLOCK_DRIVER_USE_FAST_IDLE)
101    do {
102      rtems_clock_tick();
103    } while ( _Thread_Executing == _Thread_Idle &&
104              _Thread_Heir == _Thread_Executing);
105
106  #else
107    rtems_clock_tick();
108  #endif
109}
110
111static void (*clock_handler)(void);
112
113/*
114 *  Clock_isr
115 *
116 *  This is the clock tick interrupt handler.
117 *
118 *  Input parameters:
119 *    vector - vector number
120 *
121 *  Output parameters:  NONE
122 *
123 *  Return values:      NONE
124 *
125 */
126void clockIsr(void *unused)
127{
128int decr;
129  /*
130   *  The driver has seen another tick.
131   */
132  do {
133  register uint32_t flags;
134  rtems_interrupt_disable(flags);
135  asm volatile (
136    "mfdec %0; add %0, %0, %1; mtdec %0"
137    : "=&r"(decr)
138    : "r"(Clock_Decrementer_value));
139  rtems_interrupt_enable(flags);
140
141  Clock_driver_ticks += 1;
142
143  /*
144   *  Real Time Clock counter/timer is set to automatically reload.
145   */
146  clock_handler();
147  } while ( decr < 0 );
148}
149
150/*
151 *  Clock_isr_bookE
152 *
153 *  This is the clock tick interrupt handler
154 *  for bookE CPUs. For efficiency reasons we
155 *  provide a separate handler rather than
156 *  checking the CPU type each time.
157 *
158 *  Input parameters:
159 *    vector - vector number
160 *
161 *  Output parameters:  NONE
162 *
163 *  Return values:      NONE
164 *
165 */
166void clockIsrBookE(void *unused)
167{
168  /* Note: TSR bit has already been cleared in the exception handler */
169
170  /*
171   *  The driver has seen another tick.
172   */
173
174  Clock_driver_ticks += 1;
175
176  /*
177   *  Real Time Clock counter/timer is set to automatically reload.
178   */
179  clock_handler();
180
181}
182
183int clockIsOn(void* unused)
184{
185uint32_t   msr_value;
186
187  _CPU_MSR_GET( msr_value );
188
189  if ( ppc_cpu_is_bookE() && ! (_read_BOOKE_TCR() & BOOKE_TCR_DIE) )
190    msr_value = 0;
191
192  if (msr_value & MSR_EE) return 1;
193
194  return 0;
195}
196
197
198/*
199 *  Clock_exit
200 *
201 *  This routine allows the clock driver to exit by masking the interrupt and
202 *  disabling the clock's counter.
203 *
204 *  Input parameters:   NONE
205 *
206 *  Output parameters:  NONE
207 *
208 *  Return values:      NONE
209 *
210 */
211
212void Clock_exit( void )
213{
214  (void) BSP_disconnect_clock_handler ();
215}
216 
217uint32_t Clock_driver_nanoseconds_since_last_tick(void)
218{
219  uint32_t clicks, tmp;
220
221  PPC_Get_decrementer( clicks ); 
222
223  /*
224   * Multiply by 1000 here separately from below so we do not overflow
225   * and get a negative value.
226   */
227  tmp = (Clock_Decrementer_value - clicks) * 1000;
228  tmp /= (BSP_bus_frequency/BSP_time_base_divisor);
229
230  return tmp * 1000;
231}
232
233/*
234 *  Clock_initialize
235 *
236 *  This routine initializes the clock driver.
237 *
238 *  Input parameters:
239 *    major - clock device major number
240 *    minor - clock device minor number
241 *    parg  - pointer to optional device driver arguments
242 *
243 *  Output parameters:  NONE
244 *
245 *  Return values:
246 *    rtems_device_driver status code
247 */
248rtems_device_driver Clock_initialize(
249  rtems_device_major_number major,
250  rtems_device_minor_number minor,
251  void *pargp
252)
253{
254rtems_interrupt_level l,tcr;
255
256  Clock_Decrementer_value = (BSP_bus_frequency/BSP_time_base_divisor)*
257            (rtems_configuration_get_microseconds_per_tick()/1000);
258
259  /* set the decrementer now, prior to installing the handler
260   * so no interrupts will happen in a while.
261   */
262  PPC_Set_decrementer( (unsigned)-1 );
263
264  /* On a bookE CPU the decrementer works differently. It doesn't
265   * count past zero but we can enable auto-reload :-)
266   */
267  if ( ppc_cpu_is_bookE() ) {
268
269    rtems_interrupt_disable(l);
270
271    tcr  = _read_BOOKE_TCR();
272    tcr |= BOOKE_TCR_ARE;
273    tcr &= ~BOOKE_TCR_DIE;
274    _write_BOOKE_TCR(tcr);
275
276    rtems_interrupt_enable(l);
277
278  }
279
280  /*
281   *  Set the nanoseconds since last tick handler
282   */
283  rtems_clock_set_nanoseconds_extension(
284    Clock_driver_nanoseconds_since_last_tick
285  );
286
287  /* if a decrementer exception was pending, it is cleared by
288   * executing the default (nop) handler at this point;
289   * The next exception will then be taken by our clock handler.
290   * Clock handler installation initializes the decrementer to
291   * the correct value.
292   */
293
294  clock_handler = clockHandler;
295  if (!BSP_connect_clock_handler ()) {
296    printk("Unable to initialize system clock\n");
297    rtems_fatal_error_occurred(1);
298  }
299  /* make major/minor avail to others such as shared memory driver */
300 
301  rtems_clock_major = major;
302  rtems_clock_minor = minor;
303
304  return RTEMS_SUCCESSFUL;
305} /* Clock_initialize */
306 
307/*
308 *  Clock_control
309 *
310 *  This routine is the clock device driver control entry point.
311 *
312 *  Input parameters:
313 *    major - clock device major number
314 *    minor - clock device minor number
315 *    parg  - pointer to optional device driver arguments
316 *
317 *  Output parameters:  NONE
318 *
319 *  Return values:
320 *    rtems_device_driver status code
321 */
322
323rtems_device_driver Clock_control(
324  rtems_device_major_number major,
325  rtems_device_minor_number minor,
326  void *pargp
327)
328{
329    rtems_libio_ioctl_args_t *args = pargp;
330 
331    if (args == 0)
332        goto done;
333 
334    Clock_Decrementer_value = (BSP_bus_frequency/BSP_time_base_divisor)*
335      (rtems_configuration_get_microseconds_per_tick()/1000);
336
337    if      (args->command == rtems_build_name('I', 'S', 'R', ' '))
338      clockHandler();
339    else if (args->command == rtems_build_name('N', 'E', 'W', ' '))
340    {
341        if (clock_handler == NULL)
342            Clock_initialize(major, minor, 0);
343        clock_handler = args->buffer;
344    }
345done:
346    return RTEMS_SUCCESSFUL;
347}
Note: See TracBrowser for help on using the repository browser.