source: rtems/bsps/powerpc/shared/clock/clock-ppc-dec.c @ bb99cd0d

5
Last change on this file since bb99cd0d was bb99cd0d, checked in by Sebastian Huber <sebastian.huber@…>, on Dec 5, 2019 at 6:22:33 PM

clock: Simplify driver initialization

Use a system initialization handler instead of a legacy IO driver.

Update #3834.

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