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

4.115
Last change on this file since 75acd9e was 75acd9e, checked in by Alexander Krutwig <alexander.krutwig@…>, on Apr 1, 2015 at 1:33:25 PM

bsps: Convert clock drivers to use a timecounter

Update #2271.

  • Property mode set to 100644
File size: 5.9 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
34#include <bspopts.h>   /* for CLOCK_DRIVER_USE_FAST_IDLE */
35
36SPR_RW(BOOKE_TCR)
37SPR_RW(BOOKE_TSR)
38SPR_RW(BOOKE_DECAR)
39
40extern int BSP_connect_clock_handler (void);
41
42/*
43 *  Clock ticks since initialization
44 */
45volatile uint32_t   Clock_driver_ticks;
46
47/*
48 *  This is the value programmed into the count down timer.
49 */
50static uint32_t   Clock_Decrementer_value;
51
52static struct timecounter Clock_TC;
53
54static uint32_t Clock_Get_timecount(struct timecounter *tc)
55{
56  return ppc_time_base();
57}
58
59void clockOff(void* unused)
60{
61  rtems_interrupt_level l;
62
63  if ( ppc_cpu_is_bookE() ) {
64    rtems_interrupt_disable(l);
65    _write_BOOKE_TCR(_read_BOOKE_TCR() & ~BOOKE_TCR_DIE);
66    rtems_interrupt_enable(l);
67  } else {
68    /*
69     * Nothing to do as we cannot disable all interrupts and
70     * the decrementer interrupt enable is MSR_EE
71     */
72  }
73}
74
75void clockOn(void* unused)
76{
77  rtems_interrupt_level l;
78
79  PPC_Set_decrementer( Clock_Decrementer_value );
80
81  if ( ppc_cpu_is_bookE() ) {
82    _write_BOOKE_DECAR( Clock_Decrementer_value );
83
84    rtems_interrupt_disable(l);
85
86    /* clear pending/stale irq */
87    _write_BOOKE_TSR( BOOKE_TSR_DIS );
88    /* enable */
89    _write_BOOKE_TCR( _read_BOOKE_TCR() | BOOKE_TCR_DIE );
90
91    rtems_interrupt_enable(l);
92
93  }
94}
95
96static void clockHandler(void)
97{
98  #if (CLOCK_DRIVER_USE_FAST_IDLE == 1)
99    rtems_interrupt_level level;
100    uint32_t tb;
101
102    rtems_interrupt_disable(level);
103
104    tb = ppc_time_base();
105    rtems_timecounter_tick();
106
107    while (
108      _Thread_Heir == _Thread_Executing
109        && _Thread_Executing->Start.entry_point
110          == (Thread_Entry) rtems_configuration_get_idle_task()
111    ) {
112      tb += Clock_Decrementer_value;
113      ppc_set_time_base( tb );
114      rtems_timecounter_tick();
115    }
116
117    rtems_interrupt_enable(level);
118  #else
119    rtems_timecounter_tick();
120  #endif
121}
122
123static void (*clock_handler)(void);
124
125/*
126 *  Clock_isr
127 *
128 *  This is the clock tick interrupt handler.
129 *
130 *  Input parameters:
131 *    vector - vector number
132 *
133 *  Output parameters:  NONE
134 *
135 *  Return values:      NONE
136 *
137 */
138void clockIsr(void *unused)
139{
140  int decr;
141
142  /*
143   *  The driver has seen another tick.
144   */
145  do {
146    register uint32_t flags;
147
148    rtems_interrupt_disable(flags);
149      __asm__ volatile (
150        "mfdec %0; add %0, %0, %1; mtdec %0"
151        : "=&r"(decr)
152        : "r"(Clock_Decrementer_value)
153      );
154    rtems_interrupt_enable(flags);
155
156    Clock_driver_ticks += 1;
157    /*
158     *  Real Time Clock counter/timer is set to automatically reload.
159     */
160    clock_handler();
161  } while ( decr < 0 );
162}
163
164/*
165 *  Clock_isr_bookE
166 *
167 *  This is the clock tick interrupt handler
168 *  for bookE CPUs. For efficiency reasons we
169 *  provide a separate handler rather than
170 *  checking the CPU type each time.
171 */
172void clockIsrBookE(void *unused)
173{
174  /* Note: TSR bit has already been cleared in the exception handler */
175
176  /*
177   *  The driver has seen another tick.
178   */
179
180  Clock_driver_ticks += 1;
181
182  /*
183   *  Real Time Clock counter/timer is set to automatically reload.
184   */
185  clock_handler();
186}
187
188int clockIsOn(void* unused)
189{
190  uint32_t   msr_value;
191
192  _CPU_MSR_GET( msr_value );
193
194  if ( ppc_cpu_is_bookE() && ! (_read_BOOKE_TCR() & BOOKE_TCR_DIE) )
195    msr_value = 0;
196
197  if (msr_value & MSR_EE) return 1;
198
199  return 0;
200}
201
202/*
203 *  Clock_exit
204 *
205 *  This routine allows the clock driver to exit by masking the interrupt and
206 *  disabling the clock's counter.
207 */
208void Clock_exit( void )
209{
210  (void) BSP_disconnect_clock_handler ();
211}
212
213/*
214 *  Clock_initialize
215 *
216 *  This routine initializes the clock driver.
217 */
218rtems_device_driver Clock_initialize(
219  rtems_device_major_number major,
220  rtems_device_minor_number minor,
221  void *pargp
222)
223{
224  rtems_interrupt_level l,tcr;
225
226  Clock_Decrementer_value = (BSP_bus_frequency/BSP_time_base_divisor)*
227            rtems_configuration_get_milliseconds_per_tick();
228
229  /* set the decrementer now, prior to installing the handler
230   * so no interrupts will happen in a while.
231   */
232  PPC_Set_decrementer( (unsigned)-1 );
233
234  /* On a bookE CPU the decrementer works differently. It doesn't
235   * count past zero but we can enable auto-reload :-)
236   */
237  if ( ppc_cpu_is_bookE() ) {
238
239    rtems_interrupt_disable(l);
240
241      tcr  = _read_BOOKE_TCR();
242      tcr |= BOOKE_TCR_ARE;
243      tcr &= ~BOOKE_TCR_DIE;
244      _write_BOOKE_TCR(tcr);
245
246    rtems_interrupt_enable(l);
247  }
248
249  Clock_TC.tc_get_timecount = Clock_Get_timecount;
250  Clock_TC.tc_counter_mask = 0xffffffff;
251  Clock_TC.tc_frequency = (1000 * BSP_bus_frequency) / BSP_time_base_divisor;
252  Clock_TC.tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER;
253  rtems_timecounter_install(&Clock_TC);
254
255  /*
256   * If a decrementer exception was pending, it is cleared by
257   * executing the default (nop) handler at this point;
258   * The next exception will then be taken by our clock handler.
259   * Clock handler installation initializes the decrementer to
260   * the correct value.
261   */
262  clock_handler = clockHandler;
263  if (!BSP_connect_clock_handler ()) {
264    printk("Unable to initialize system clock\n");
265    rtems_fatal_error_occurred(1);
266  }
267
268  return RTEMS_SUCCESSFUL;
269} /* Clock_initialize */
Note: See TracBrowser for help on using the repository browser.