source: rtems/c/src/lib/libcpu/powerpc/mpc6xx/clock/c_clock.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: 6.0 KB
Line 
1/**
2 *  @brief 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
10/*
11 *  COPYRIGHT (c) 1989-2014.
12 *  On-Line Applications Research Corporation (OAR).
13 *
14 *  The license and distribution terms for this file may in
15 *  the file LICENSE in this distribution or at
16 *  http://www.rtems.org/license/LICENSE.
17 *
18 *  Modified to support the MPC750.
19 *  Modifications Copyright (c) 1999 Eric Valette valette@crf.canon.fr
20 */
21
22#include <rtems.h>
23#include <rtems/libio.h>
24#include <rtems/clockdrv.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#include <libcpu/powerpc-utility.h>
32#include <rtems/timecounter.h>
33#include <rtems/score/percpu.h>
34
35#include <bspopts.h>   /* for CLOCK_DRIVER_USE_FAST_IDLE */
36
37SPR_RW(BOOKE_TCR)
38SPR_RW(BOOKE_TSR)
39SPR_RW(BOOKE_DECAR)
40
41extern int BSP_connect_clock_handler (void);
42
43/*
44 *  Clock ticks since initialization
45 */
46volatile uint32_t   Clock_driver_ticks;
47
48/*
49 *  This is the value programmed into the count down timer.
50 */
51static uint32_t   Clock_Decrementer_value;
52
53static struct timecounter Clock_TC;
54
55static uint32_t Clock_Get_timecount(struct timecounter *tc)
56{
57  return ppc_time_base();
58}
59
60void clockOff(void* unused)
61{
62  rtems_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{
78  rtems_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  #if (CLOCK_DRIVER_USE_FAST_IDLE == 1)
100    rtems_interrupt_level level;
101    uint32_t tb;
102
103    rtems_interrupt_disable(level);
104
105    tb = ppc_time_base();
106    rtems_timecounter_tick();
107
108    while (
109      _Thread_Heir == _Thread_Executing
110        && _Thread_Executing->Start.entry_point
111          == (Thread_Entry) rtems_configuration_get_idle_task()
112    ) {
113      tb += Clock_Decrementer_value;
114      ppc_set_time_base( tb );
115      rtems_timecounter_tick();
116    }
117
118    rtems_interrupt_enable(level);
119  #else
120    rtems_timecounter_tick();
121  #endif
122}
123
124static void (*clock_handler)(void);
125
126/*
127 *  Clock_isr
128 *
129 *  This is the clock tick interrupt handler.
130 *
131 *  Input parameters:
132 *    vector - vector number
133 *
134 *  Output parameters:  NONE
135 *
136 *  Return values:      NONE
137 *
138 */
139void clockIsr(void *unused)
140{
141  int decr;
142
143  /*
144   *  The driver has seen another tick.
145   */
146  do {
147    register uint32_t flags;
148
149    rtems_interrupt_disable(flags);
150      __asm__ volatile (
151        "mfdec %0; add %0, %0, %1; mtdec %0"
152        : "=&r"(decr)
153        : "r"(Clock_Decrementer_value)
154      );
155    rtems_interrupt_enable(flags);
156
157    Clock_driver_ticks += 1;
158    /*
159     *  Real Time Clock counter/timer is set to automatically reload.
160     */
161    clock_handler();
162  } while ( decr < 0 );
163}
164
165/*
166 *  Clock_isr_bookE
167 *
168 *  This is the clock tick interrupt handler
169 *  for bookE CPUs. For efficiency reasons we
170 *  provide a separate handler rather than
171 *  checking the CPU type each time.
172 */
173void clockIsrBookE(void *unused)
174{
175  /* Note: TSR bit has already been cleared in the exception handler */
176
177  /*
178   *  The driver has seen another tick.
179   */
180
181  Clock_driver_ticks += 1;
182
183  /*
184   *  Real Time Clock counter/timer is set to automatically reload.
185   */
186  clock_handler();
187}
188
189int clockIsOn(void* unused)
190{
191  uint32_t   msr_value;
192
193  _CPU_MSR_GET( msr_value );
194
195  if ( ppc_cpu_is_bookE() && ! (_read_BOOKE_TCR() & BOOKE_TCR_DIE) )
196    msr_value = 0;
197
198  if (msr_value & MSR_EE) return 1;
199
200  return 0;
201}
202
203/*
204 *  Clock_exit
205 *
206 *  This routine allows the clock driver to exit by masking the interrupt and
207 *  disabling the clock's counter.
208 */
209void Clock_exit( void )
210{
211  (void) BSP_disconnect_clock_handler ();
212}
213
214/*
215 *  Clock_initialize
216 *
217 *  This routine initializes the clock driver.
218 */
219rtems_device_driver Clock_initialize(
220  rtems_device_major_number major,
221  rtems_device_minor_number minor,
222  void *pargp
223)
224{
225  rtems_interrupt_level l,tcr;
226
227  Clock_Decrementer_value = (BSP_bus_frequency/BSP_time_base_divisor)*
228            rtems_configuration_get_milliseconds_per_tick();
229
230  /* set the decrementer now, prior to installing the handler
231   * so no interrupts will happen in a while.
232   */
233  PPC_Set_decrementer( (unsigned)-1 );
234
235  /* On a bookE CPU the decrementer works differently. It doesn't
236   * count past zero but we can enable auto-reload :-)
237   */
238  if ( ppc_cpu_is_bookE() ) {
239
240    rtems_interrupt_disable(l);
241
242      tcr  = _read_BOOKE_TCR();
243      tcr |= BOOKE_TCR_ARE;
244      tcr &= ~BOOKE_TCR_DIE;
245      _write_BOOKE_TCR(tcr);
246
247    rtems_interrupt_enable(l);
248  }
249
250  Clock_TC.tc_get_timecount = Clock_Get_timecount;
251  Clock_TC.tc_counter_mask = 0xffffffff;
252  Clock_TC.tc_frequency = (UINT64_C(1000) * BSP_bus_frequency) / BSP_time_base_divisor;
253  Clock_TC.tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER;
254  rtems_timecounter_install(&Clock_TC);
255
256  /*
257   * If a decrementer exception was pending, it is cleared by
258   * executing the default (nop) handler at this point;
259   * The next exception will then be taken by our clock handler.
260   * Clock handler installation initializes the decrementer to
261   * the correct value.
262   */
263  clock_handler = clockHandler;
264  if (!BSP_connect_clock_handler ()) {
265    printk("Unable to initialize system clock\n");
266    rtems_fatal_error_occurred(1);
267  }
268
269  return RTEMS_SUCCESSFUL;
270} /* Clock_initialize */
Note: See TracBrowser for help on using the repository browser.