source: rtems/bsps/sparc/leon3/clock/ckinit.c @ d952d73

5
Last change on this file since d952d73 was d952d73, checked in by Daniel Hellstrom <daniel@…>, on 11/21/17 at 10:09:58

leon3: fix warning when SMP is enabled

  • Property mode set to 100644
File size: 7.2 KB
Line 
1/*
2 *  Clock Tick Device Driver
3 *
4 *  This routine initializes LEON timer 1 which used for the clock tick.
5 *
6 *  The tick frequency is directly programmed to the configured number of
7 *  microseconds per tick.
8 *
9 *  COPYRIGHT (c) 1989-2006.
10 *  On-Line Applications Research Corporation (OAR).
11 *
12 *  Modified for LEON3 BSP.
13 *  COPYRIGHT (c) 2004.
14 *  Gaisler Research.
15 *
16 *  Copyright (c) 2014, 2018 embedded brains GmbH
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 <bsp.h>
24#include <bsp/irq.h>
25#include <bspopts.h>
26#include <bsp/fatal.h>
27#include <rtems/rtems/intr.h>
28#include <ambapp.h>
29#include <rtems/score/profiling.h>
30#include <rtems/timecounter.h>
31
32/* The LEON3 BSP Timer driver can rely on the Driver Manager if the
33 * DrvMgr is initialized during startup. Otherwise the classic driver
34 * must be used.
35 *
36 * The DrvMgr Clock driver is located in the shared/timer directory
37 */
38#ifndef RTEMS_DRVMGR_STARTUP
39
40/* LEON3 Timer system interrupt number */
41static int clkirq;
42
43static void (*leon3_tc_tick)(void);
44
45static rtems_timecounter_simple leon3_tc;
46
47#ifndef RTEMS_SMP
48static uint32_t leon3_tc_get(rtems_timecounter_simple *tc)
49{
50  return LEON3_Timer_Regs->timer[LEON3_CLOCK_INDEX].value;
51}
52
53static bool leon3_tc_is_pending(rtems_timecounter_simple *tc)
54{
55  return LEON_Is_interrupt_pending(clkirq);
56}
57
58static void leon3_tc_at_tick( rtems_timecounter_simple *tc )
59{
60  /* Nothing to do */
61}
62
63static uint32_t leon3_tc_get_timecount(struct timecounter *tc)
64{
65  return rtems_timecounter_simple_downcounter_get(
66    tc,
67    leon3_tc_get,
68    leon3_tc_is_pending
69  );
70}
71
72static void leon3_tc_tick_simple(void)
73{
74  rtems_timecounter_simple_downcounter_tick(
75    &leon3_tc,
76    leon3_tc_get,
77    leon3_tc_at_tick
78  );
79}
80#endif
81
82static uint32_t leon3_tc_get_timecount_up_counter(struct timecounter *tc)
83{
84  return leon3_up_counter_low();
85}
86
87static uint32_t leon3_tc_get_timecount_irqmp(struct timecounter *tc)
88{
89  return LEON3_IrqCtrl_Regs->timestamp[0].counter;
90}
91
92#ifdef RTEMS_SMP
93static uint32_t leon3_tc_get_timecount_second_timer(struct timecounter *tc)
94{
95  return 0xffffffff - LEON3_Timer_Regs->timer[LEON3_CLOCK_INDEX + 1].value;
96}
97#endif
98
99#ifdef RTEMS_PROFILING
100#define IRQMP_TIMESTAMP_S1_S2 ((1U << 25) | (1U << 26))
101
102static void leon3_tc_tick_irqmp_timestamp(void)
103{
104  volatile struct irqmp_timestamp_regs *irqmp_ts =
105    &LEON3_IrqCtrl_Regs->timestamp[0];
106  unsigned int first = irqmp_ts->assertion;
107  unsigned int second = irqmp_ts->counter;
108
109  irqmp_ts->control |= IRQMP_TIMESTAMP_S1_S2;
110
111  _Profiling_Update_max_interrupt_delay(_Per_CPU_Get(), second - first);
112
113  rtems_timecounter_tick();
114}
115#endif
116
117static void leon3_tc_tick_irqmp_timestamp_init(void)
118{
119#ifdef RTEMS_PROFILING
120  /*
121   * Ignore the first clock interrupt, since it contains the sequential system
122   * initialization time.  Do the timestamp initialization on the fly.
123   */
124
125#ifdef RTEMS_SMP
126  static Atomic_Uint counter = ATOMIC_INITIALIZER_UINT(0);
127
128  bool done =
129    _Atomic_Fetch_add_uint(&counter, 1, ATOMIC_ORDER_RELAXED)
130      == rtems_get_processor_count() - 1;
131#else
132  bool done = true;
133#endif
134
135  volatile struct irqmp_timestamp_regs *irqmp_ts =
136    &LEON3_IrqCtrl_Regs->timestamp[0];
137  unsigned int ks = 1U << 5;
138
139  irqmp_ts->control = ks | IRQMP_TIMESTAMP_S1_S2 | (unsigned int) clkirq;
140
141  if (done) {
142    leon3_tc_tick = leon3_tc_tick_irqmp_timestamp;
143  }
144#endif
145
146  rtems_timecounter_tick();
147}
148
149#ifdef RTEMS_SMP
150static void leon3_tc_tick_second_timer(void)
151{
152  rtems_timecounter_tick();
153}
154#endif
155
156static void leon3_tc_do_tick(void)
157{
158  (*leon3_tc_tick)();
159}
160
161#define Adjust_clkirq_for_node() do { clkirq += LEON3_CLOCK_INDEX; } while(0)
162
163#define Clock_driver_support_find_timer() \
164  do { \
165    /* Assume timer found during BSP initialization */ \
166    if (LEON3_Timer_Regs) { \
167      clkirq = (LEON3_Timer_Regs->cfg & 0xf8) >> 3; \
168      \
169      Adjust_clkirq_for_node(); \
170    } \
171  } while (0)
172
173#define Clock_driver_support_install_isr( _new ) \
174  bsp_clock_handler_install(_new)
175
176static void bsp_clock_handler_install(rtems_isr *new)
177{
178  rtems_status_code sc;
179
180  sc = rtems_interrupt_handler_install(
181    clkirq,
182    "Clock",
183    RTEMS_INTERRUPT_UNIQUE,
184    new,
185    NULL
186  );
187  if (sc != RTEMS_SUCCESSFUL) {
188    rtems_fatal(RTEMS_FATAL_SOURCE_BSP, LEON3_FATAL_CLOCK_INITIALIZATION);
189  }
190}
191
192#define Clock_driver_support_set_interrupt_affinity(online_processors) \
193  bsp_interrupt_set_affinity(clkirq, online_processors)
194
195static void leon3_clock_initialize(void)
196{
197  volatile struct irqmp_timestamp_regs *irqmp_ts;
198  volatile struct gptimer_regs *gpt;
199
200  irqmp_ts = &LEON3_IrqCtrl_Regs->timestamp[0];
201  gpt = LEON3_Timer_Regs;
202
203  gpt->timer[LEON3_CLOCK_INDEX].reload =
204    rtems_configuration_get_microseconds_per_tick() - 1;
205  gpt->timer[LEON3_CLOCK_INDEX].ctrl =
206    GPTIMER_TIMER_CTRL_EN | GPTIMER_TIMER_CTRL_RS |
207      GPTIMER_TIMER_CTRL_LD | GPTIMER_TIMER_CTRL_IE;
208
209  leon3_up_counter_enable();
210
211  if (leon3_up_counter_is_available()) {
212    /* Use the LEON4 up-counter if available */
213    leon3_tc.tc.tc_get_timecount = leon3_tc_get_timecount_up_counter;
214    leon3_tc.tc.tc_counter_mask = 0xffffffff;
215    leon3_tc.tc.tc_frequency = leon3_up_counter_frequency();
216    leon3_tc.tc.tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER;
217
218#ifdef RTEMS_PROFILING
219    if (!leon3_irqmp_has_timestamp(irqmp_ts)) {
220      bsp_fatal(LEON3_FATAL_CLOCK_NO_IRQMP_TIMESTAMP_SUPPORT);
221    }
222#endif
223
224    leon3_tc_tick = leon3_tc_tick_irqmp_timestamp_init;
225    rtems_timecounter_install(&leon3_tc.tc);
226  } else if (leon3_irqmp_has_timestamp(irqmp_ts)) {
227    /* Use the interrupt controller timestamp counter if available */
228    leon3_tc.tc.tc_get_timecount = leon3_tc_get_timecount_irqmp;
229    leon3_tc.tc.tc_counter_mask = 0xffffffff;
230    leon3_tc.tc.tc_frequency = ambapp_freq_get(&ambapp_plb, LEON3_Timer_Adev);
231    leon3_tc.tc.tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER;
232    leon3_tc_tick = leon3_tc_tick_irqmp_timestamp_init;
233
234    /*
235     * At least one TSISEL field must be non-zero to enable the timestamp
236     * counter.  Use an arbitrary interrupt source.
237     */
238    irqmp_ts->control = 0x1;
239
240    rtems_timecounter_install(&leon3_tc.tc);
241  } else {
242#ifdef RTEMS_SMP
243    /*
244     * The GR712RC for example has no timestamp unit in the interrupt
245     * controller.  At least on SMP configurations we must use a second timer
246     * in free running mode for the timecounter.
247     */
248    gpt->timer[LEON3_CLOCK_INDEX + 1].ctrl =
249      GPTIMER_TIMER_CTRL_EN | GPTIMER_TIMER_CTRL_IE;
250    leon3_tc.tc.tc_get_timecount = leon3_tc_get_timecount_second_timer;
251    leon3_tc.tc.tc_counter_mask = 0xffffffff;
252    leon3_tc.tc.tc_frequency = LEON3_GPTIMER_0_FREQUENCY_SET_BY_BOOT_LOADER;
253    leon3_tc.tc.tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER;
254    leon3_tc_tick = leon3_tc_tick_second_timer;
255    rtems_timecounter_install(&leon3_tc.tc);
256#else
257    leon3_tc_tick = leon3_tc_tick_simple;
258    rtems_timecounter_simple_install(
259      &leon3_tc,
260      LEON3_GPTIMER_0_FREQUENCY_SET_BY_BOOT_LOADER,
261      rtems_configuration_get_microseconds_per_tick(),
262      leon3_tc_get_timecount
263    );
264#endif
265  }
266}
267
268#define Clock_driver_support_initialize_hardware() \
269  leon3_clock_initialize()
270
271#define Clock_driver_timecounter_tick() leon3_tc_do_tick()
272
273#include "../../../shared/dev/clock/clockimpl.h"
274
275#endif
Note: See TracBrowser for help on using the repository browser.