source: rtems/c/src/lib/libbsp/powerpc/shared/clock/clock.c @ 75acd9e

4.115
Last change on this file since 75acd9e was 75acd9e, checked in by Alexander Krutwig <alexander.krutwig@…>, on 04/01/15 at 13:33:25

bsps: Convert clock drivers to use a timecounter

Update #2271.

  • Property mode set to 100644
File size: 5.9 KB
Line 
1/**
2 * @file
3 *
4 * @ingroup powerpc_shared
5 *
6 * @brief Source file for a clock driver.
7 */
8
9/*
10 * Copyright (c) 2008-2015 embedded brains GmbH.  All rights reserved.
11 *
12 *  embedded brains GmbH
13 *  Obere Lagerstr. 30
14 *  82178 Puchheim
15 *  Germany
16 *  <rtems@embedded-brains.de>
17 *
18 * The license and distribution terms for this file may be
19 * found in the file LICENSE in this distribution or at
20 * http://www.rtems.org/license/LICENSE.
21 */
22
23#include <rtems.h>
24#include <rtems/clockdrv.h>
25#include <rtems/timecounter.h>
26
27#include <libcpu/powerpc-utility.h>
28#include <bsp/vectors.h>
29
30#define RTEMS_STATUS_CHECKS_USE_PRINTK
31
32#include <rtems/status-checks.h>
33
34/*
35 * This variable must be defined in the BSP and valid before clock driver
36 * initialization.
37 */
38extern uint32_t bsp_time_base_frequency;
39
40#define PPC405_PIT 0x3db
41
42#define PPC_CLOCK_DECREMENTER_MAX UINT32_MAX
43
44volatile uint32_t Clock_driver_ticks = 0;
45
46static uint32_t ppc_clock_decrementer_value = PPC_CLOCK_DECREMENTER_MAX;
47
48static uint32_t ppc_clock_next_time_base;
49
50static struct timecounter ppc_tc;
51
52static uint32_t ppc_get_timecount(struct timecounter *tc)
53{
54  return ppc_time_base();
55}
56
57static void ppc_clock_no_tick(void)
58{
59  /* Do nothing */
60}
61
62static void (*ppc_clock_tick)(void) = ppc_clock_no_tick;
63
64static int ppc_clock_exception_handler(
65  BSP_Exception_frame *frame,
66  unsigned number
67)
68{
69  uint32_t delta = ppc_clock_decrementer_value;
70  uint32_t next = ppc_clock_next_time_base;
71  uint32_t dec = 0;
72  uint32_t now = 0;
73  uint32_t msr = 0;
74
75  do {
76    /* Increment clock ticks */
77    Clock_driver_ticks += 1;
78
79    /* Enable external exceptions */
80    msr = ppc_external_exceptions_enable();
81
82    /* Call clock ticker  */
83    ppc_clock_tick();
84
85    /* Restore machine state */
86    ppc_external_exceptions_disable( msr);
87
88    /* Next time base */
89    next += delta;
90
91    /* Current time */
92    now = ppc_time_base();
93
94    /* New decrementer value */
95    dec = next - now;
96  } while (dec > delta);
97
98  /* Set decrementer */
99  ppc_set_decrementer_register( dec);
100
101  /* Expected next time base */
102  ppc_clock_next_time_base = next;
103
104  return 0;
105}
106
107static int ppc_clock_exception_handler_first(
108  BSP_Exception_frame *frame,
109  unsigned number
110)
111{
112  /* We have to clear the first pending decrementer exception this way */
113
114  if (ppc_decrementer_register() >= 0x80000000) {
115    ppc_clock_exception_handler( frame, number);
116  }
117
118  ppc_exc_set_handler( ASM_DEC_VECTOR, ppc_clock_exception_handler);
119
120  return 0;
121}
122
123static int ppc_clock_exception_handler_booke(
124  BSP_Exception_frame *frame,
125  unsigned number
126)
127{
128  uint32_t msr;
129
130  /* Acknowledge decrementer request */
131  PPC_SET_SPECIAL_PURPOSE_REGISTER( BOOKE_TSR, BOOKE_TSR_DIS);
132
133  /* Increment clock ticks */
134  Clock_driver_ticks += 1;
135
136  /* Enable external exceptions */
137  msr = ppc_external_exceptions_enable();
138
139  /* Call clock ticker  */
140  ppc_clock_tick();
141
142  /* Restore machine state */
143  ppc_external_exceptions_disable( msr);
144
145  return 0;
146}
147
148static int ppc_clock_exception_handler_ppc405(BSP_Exception_frame *frame, unsigned number)
149{
150  uint32_t msr;
151
152  /* Acknowledge PIT request */
153  PPC_SET_SPECIAL_PURPOSE_REGISTER(PPC405_TSR, BOOKE_TSR_DIS);
154
155  /* Increment clock ticks */
156  Clock_driver_ticks += 1;
157
158  /* Enable external exceptions */
159  msr = ppc_external_exceptions_enable();
160
161  /* Call clock ticker  */
162  ppc_clock_tick();
163
164  /* Restore machine state */
165  ppc_external_exceptions_disable(msr);
166
167  return 0;
168}
169
170void Clock_exit(void)
171{
172  /* Set the decrementer to the maximum value */
173  ppc_set_decrementer_register( PPC_CLOCK_DECREMENTER_MAX);
174
175  /* Use default clock handler */
176  ppc_clock_tick = ppc_clock_no_tick;
177}
178
179rtems_device_driver Clock_initialize(
180  rtems_device_major_number major,
181  rtems_device_minor_number minor,
182  void *arg
183)
184{
185  uint64_t frequency = bsp_time_base_frequency;
186  uint64_t us_per_tick = rtems_configuration_get_microseconds_per_tick();
187  uint32_t interval = (uint32_t) ((frequency * us_per_tick) / 1000000);
188  uint32_t mask;
189
190  /*
191   * Set default ticker.
192   */
193  ppc_clock_tick = rtems_timecounter_tick;
194
195  if (ppc_cpu_is_bookE() != PPC_BOOKE_405) {
196    /* Decrementer value */
197    ppc_clock_decrementer_value = interval - 1;
198
199    /* Check decrementer value */
200    if (ppc_clock_decrementer_value == 0) {
201      ppc_clock_decrementer_value = PPC_CLOCK_DECREMENTER_MAX;
202      RTEMS_SYSLOG_ERROR( "decrementer value would be zero, will be set to maximum value instead\n");
203    }
204    if (ppc_cpu_is_bookE()) {
205      /* Set decrementer auto-reload value */
206      PPC_SET_SPECIAL_PURPOSE_REGISTER( BOOKE_DECAR, ppc_clock_decrementer_value);
207
208      /* Install exception handler */
209      ppc_exc_set_handler( ASM_BOOKE_DEC_VECTOR, ppc_clock_exception_handler_booke);
210
211      /* Enable decrementer and auto-reload */
212      PPC_SET_SPECIAL_PURPOSE_REGISTER_BITS( BOOKE_TCR, BOOKE_TCR_DIE | BOOKE_TCR_ARE);
213    } else {
214      /* Here the decrementer value is actually the interval */
215      ++ppc_clock_decrementer_value;
216
217      /* Initialize next time base */
218      ppc_clock_next_time_base = ppc_time_base() + ppc_clock_decrementer_value;
219
220      /* Install exception handler */
221      ppc_exc_set_handler( ASM_DEC_VECTOR, ppc_clock_exception_handler_first);
222    }
223
224    /* Set the decrementer value */
225    ppc_set_decrementer_register( ppc_clock_decrementer_value);
226  } else {
227    /* PIT interval value */
228    ppc_clock_decrementer_value = interval;
229
230    /* Install exception handler */
231    ppc_exc_set_handler(ASM_BOOKE_DEC_VECTOR, ppc_clock_exception_handler_ppc405);
232
233    /* Enable PIT and auto-reload */
234    PPC_SET_SPECIAL_PURPOSE_REGISTER_BITS(PPC405_TCR, BOOKE_TCR_DIE | BOOKE_TCR_ARE);
235
236    /* Set PIT auto-reload and initial value */
237    PPC_SET_SPECIAL_PURPOSE_REGISTER(PPC405_PIT, interval);
238  }
239
240  /* Install timecounter */
241  ppc_tc.tc_get_timecount = ppc_get_timecount;
242  ppc_tc.tc_counter_mask = 0xffffffff;
243  ppc_tc.tc_frequency = frequency;
244  ppc_tc.tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER;
245  rtems_timecounter_install(&ppc_tc);
246
247  return RTEMS_SUCCESSFUL;
248}
Note: See TracBrowser for help on using the repository browser.