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

4.104.114.84.95
Last change on this file since f7588eba was f7588eba, checked in by Joel Sherrill <joel.sherrill@…>, on Apr 17, 2007 at 5:41:19 PM

2007-04-17 Joel Sherrill <joel@…>

  • mpc6xx/clock/c_clock.c: Add initial cut at nanoseconds since last tick handler.
  • Property mode set to 100644
File size: 5.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 <rtems/bspIo.h>                     /* for printk() */
29
30extern int BSP_connect_clock_handler (void);
31
32/*
33 *  Clock ticks since initialization
34 */
35
36volatile uint32_t   Clock_driver_ticks;
37
38/*
39 *  This is the value programmed into the count down timer.
40 */
41
42uint32_t   Clock_Decrementer_value;
43
44/*
45 * These are set by clock driver during its init
46 */
47 
48rtems_device_major_number rtems_clock_major = ~0;
49rtems_device_minor_number rtems_clock_minor;
50
51void clockOff(void* unused)
52{
53  /*
54   * Nothing to do as we cannot disable all interrupts and
55   * the decrementer interrupt enable is MSR_EE
56   */
57}
58void clockOn(void* unused)
59{
60  PPC_Set_decrementer( Clock_Decrementer_value );
61}
62
63static void clockHandler(void)
64{
65    rtems_clock_tick();
66}
67
68static void (*clock_handler)(void);
69
70/*
71 *  Clock_isr
72 *
73 *  This is the clock tick interrupt handler.
74 *
75 *  Input parameters:
76 *    vector - vector number
77 *
78 *  Output parameters:  NONE
79 *
80 *  Return values:      NONE
81 *
82 */
83void clockIsr(void *unused)
84{
85int decr;
86  /*
87   *  The driver has seen another tick.
88   */
89  do {
90        register uint32_t flags;
91        rtems_interrupt_disable(flags);
92        asm volatile ("mfdec %0; add %0, %0, %1; mtdec %0":"=&r"(decr):"r"(Clock_Decrementer_value));
93        rtems_interrupt_enable(flags);
94
95        Clock_driver_ticks += 1;
96
97        /*
98         *  Real Time Clock counter/timer is set to automatically reload.
99         */
100        clock_handler();
101  } while ( decr < 0 );
102}
103
104int clockIsOn(void* unused)
105{
106  uint32_t   msr_value;
107
108  _CPU_MSR_GET( msr_value );
109  if (msr_value & MSR_EE) return 1;
110  return 0;
111}
112
113
114/*
115 *  Clock_exit
116 *
117 *  This routine allows the clock driver to exit by masking the interrupt and
118 *  disabling the clock's counter.
119 *
120 *  Input parameters:   NONE
121 *
122 *  Output parameters:  NONE
123 *
124 *  Return values:      NONE
125 *
126 */
127
128void Clock_exit( void )
129{
130  (void) BSP_disconnect_clock_handler ();
131}
132 
133uint32_t Clock_driver_nanoseconds_since_last_tick(void)
134{
135  uint32_t clicks, tmp;
136
137  PPC_Get_decrementer( clicks ); 
138
139  tmp = (Clock_Decrementer_value - clicks) * 1000000;
140  tmp /= (BSP_bus_frequency/BSP_time_base_divisor);
141
142  return tmp;
143}
144
145/*
146 *  Clock_initialize
147 *
148 *  This routine initializes the clock driver.
149 *
150 *  Input parameters:
151 *    major - clock device major number
152 *    minor - clock device minor number
153 *    parg  - pointer to optional device driver arguments
154 *
155 *  Output parameters:  NONE
156 *
157 *  Return values:
158 *    rtems_device_driver status code
159 */
160rtems_device_driver Clock_initialize(
161  rtems_device_major_number major,
162  rtems_device_minor_number minor,
163  void *pargp
164)
165{
166  Clock_Decrementer_value = (BSP_bus_frequency/BSP_time_base_divisor)*
167            (rtems_configuration_get_microseconds_per_tick()/1000);
168
169  /* set the decrementer now, prior to installing the handler
170   * so no interrupts will happen in a while.
171   */
172  PPC_Set_decrementer( (unsigned)-1 );
173
174  /*
175   *  Set the nanoseconds since last tick handler
176   */
177  rtems_clock_set_nanoseconds_extension(
178    Clock_driver_nanoseconds_since_last_tick
179  );
180
181  /* if a decrementer exception was pending, it is cleared by
182   * executing the default (nop) handler at this point;
183   * The next exception will then be taken by our clock handler.
184   * Clock handler installation initializes the decrementer to
185   * the correct value.
186   */
187
188  clock_handler = clockHandler;
189  if (!BSP_connect_clock_handler ()) {
190    printk("Unable to initialize system clock\n");
191    rtems_fatal_error_occurred(1);
192  }
193  /* make major/minor avail to others such as shared memory driver */
194 
195  rtems_clock_major = major;
196  rtems_clock_minor = minor;
197
198  return RTEMS_SUCCESSFUL;
199} /* Clock_initialize */
200 
201/*
202 *  Clock_control
203 *
204 *  This routine is the clock device driver control entry point.
205 *
206 *  Input parameters:
207 *    major - clock device major number
208 *    minor - clock device minor number
209 *    parg  - pointer to optional device driver arguments
210 *
211 *  Output parameters:  NONE
212 *
213 *  Return values:
214 *    rtems_device_driver status code
215 */
216
217rtems_device_driver Clock_control(
218  rtems_device_major_number major,
219  rtems_device_minor_number minor,
220  void *pargp
221)
222{
223    rtems_libio_ioctl_args_t *args = pargp;
224 
225    if (args == 0)
226        goto done;
227 
228    Clock_Decrementer_value = (BSP_bus_frequency/BSP_time_base_divisor)*
229      (rtems_configuration_get_microseconds_per_tick()/1000);
230
231    if      (args->command == rtems_build_name('I', 'S', 'R', ' '))
232      clockHandler();
233    else if (args->command == rtems_build_name('N', 'E', 'W', ' '))
234    {
235        if (clock_handler == NULL)
236            Clock_initialize(major, minor, 0);
237        clock_handler = args->buffer;
238    }
239done:
240    return RTEMS_SUCCESSFUL;
241}
Note: See TracBrowser for help on using the repository browser.