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

Last change on this file since e1a0e0c3 was e1a0e0c3, checked in by Sebastian Huber <sebastian.huber@…>, on 10/08/20 at 05:50:10

grlib: Add and use irqmp_has_timestamp()

Replace leon3_irqmp_has_timestamp() with irqmp_has_timestamp() and move
it to grlib.h.

Close #4128.

  • Property mode set to 100644
File size: 6.4 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 <grlib/ambapp.h>
29#include <rtems/score/profiling.h>
30#include <rtems/score/sparcimpl.h>
31#include <rtems/timecounter.h>
32
33/* The LEON3 BSP Timer driver can rely on the Driver Manager if the
34 * DrvMgr is initialized during startup. Otherwise the classic driver
35 * must be used.
36 *
37 * The DrvMgr Clock driver is located in the shared/timer directory
38 */
39#ifndef RTEMS_DRVMGR_STARTUP
40
41/* LEON3 Timer system interrupt number */
42static int clkirq;
43
44static void (*leon3_tc_tick)(void);
45
46static struct timecounter leon3_tc;
47
48#ifdef RTEMS_PROFILING
49#define IRQMP_TIMESTAMP_S1_S2 ((1U << 25) | (1U << 26))
50
51static void leon3_tc_tick_irqmp_timestamp(void)
52{
53  volatile struct irqmp_timestamp_regs *irqmp_ts =
54    &LEON3_IrqCtrl_Regs->timestamp[0];
55  unsigned int first = irqmp_ts->assertion;
56  unsigned int second = irqmp_ts->counter;
57
58  irqmp_ts->control |= IRQMP_TIMESTAMP_S1_S2;
59
60  _Profiling_Update_max_interrupt_delay(_Per_CPU_Get(), second - first);
61
62  rtems_timecounter_tick();
63}
64#endif
65
66static void leon3_tc_tick_irqmp_timestamp_init(void)
67{
68#ifdef RTEMS_PROFILING
69  /*
70   * Ignore the first clock interrupt, since it contains the sequential system
71   * initialization time.  Do the timestamp initialization on the fly.
72   */
73
74#ifdef RTEMS_SMP
75  static Atomic_Uint counter = ATOMIC_INITIALIZER_UINT(0);
76
77  bool done =
78    _Atomic_Fetch_add_uint(&counter, 1, ATOMIC_ORDER_RELAXED)
79      == rtems_scheduler_get_processor_maximum() - 1;
80#else
81  bool done = true;
82#endif
83
84  volatile struct irqmp_timestamp_regs *irqmp_ts =
85    &LEON3_IrqCtrl_Regs->timestamp[0];
86  unsigned int ks = 1U << 5;
87
88  irqmp_ts->control = ks | IRQMP_TIMESTAMP_S1_S2 | (unsigned int) clkirq;
89
90  if (done) {
91    leon3_tc_tick = leon3_tc_tick_irqmp_timestamp;
92  }
93#endif
94
95  rtems_timecounter_tick();
96}
97
98static void leon3_tc_tick_default(void)
99{
100#ifndef RTEMS_SMP
101  SPARC_Counter *counter;
102  rtems_interrupt_level level;
103
104  counter = &_SPARC_Counter_mutable;
105  rtems_interrupt_local_disable(level);
106
107  LEON3_IrqCtrl_Regs->iclear = counter->pending_mask;
108  counter->accumulated += counter->interval;
109
110  rtems_interrupt_local_enable(level);
111#endif
112
113  rtems_timecounter_tick();
114}
115
116static void leon3_tc_do_tick(void)
117{
118  (*leon3_tc_tick)();
119}
120
121#define Adjust_clkirq_for_node() do { clkirq += LEON3_CLOCK_INDEX; } while(0)
122
123#define Clock_driver_support_find_timer() \
124  do { \
125    /* Assume timer found during BSP initialization */ \
126    if (LEON3_Timer_Regs) { \
127      clkirq = (LEON3_Timer_Regs->cfg & 0xf8) >> 3; \
128      \
129      Adjust_clkirq_for_node(); \
130    } \
131  } while (0)
132
133#define Clock_driver_support_install_isr( _new ) \
134  bsp_clock_handler_install(_new)
135
136static void bsp_clock_handler_install(rtems_isr *new)
137{
138  rtems_status_code sc;
139
140  sc = rtems_interrupt_handler_install(
141    clkirq,
142    "Clock",
143    RTEMS_INTERRUPT_UNIQUE,
144    new,
145    NULL
146  );
147  if (sc != RTEMS_SUCCESSFUL) {
148    rtems_fatal(RTEMS_FATAL_SOURCE_BSP, LEON3_FATAL_CLOCK_INITIALIZATION);
149  }
150}
151
152#define Clock_driver_support_set_interrupt_affinity(online_processors) \
153  bsp_interrupt_set_affinity(clkirq, online_processors)
154
155static void leon3_clock_initialize(void)
156{
157  volatile struct irqmp_timestamp_regs *irqmp_ts;
158  volatile struct gptimer_regs *gpt;
159  struct timecounter *tc;
160
161  irqmp_ts = &LEON3_IrqCtrl_Regs->timestamp[0];
162  gpt = LEON3_Timer_Regs;
163  tc = &leon3_tc;
164
165  gpt->timer[LEON3_CLOCK_INDEX].reload =
166    rtems_configuration_get_microseconds_per_tick() - 1;
167  gpt->timer[LEON3_CLOCK_INDEX].ctrl =
168    GPTIMER_TIMER_CTRL_EN | GPTIMER_TIMER_CTRL_RS |
169      GPTIMER_TIMER_CTRL_LD | GPTIMER_TIMER_CTRL_IE;
170
171  leon3_up_counter_enable();
172
173  if (leon3_up_counter_is_available()) {
174    /* Use the LEON4 up-counter if available */
175    tc->tc_get_timecount = _SPARC_Get_timecount_asr23;
176    tc->tc_frequency = leon3_up_counter_frequency();
177
178#ifdef RTEMS_PROFILING
179    if (!irqmp_has_timestamp(irqmp_ts)) {
180      bsp_fatal(LEON3_FATAL_CLOCK_NO_IRQMP_TIMESTAMP_SUPPORT);
181    }
182#endif
183
184    leon3_tc_tick = leon3_tc_tick_irqmp_timestamp_init;
185  } else if (irqmp_has_timestamp(irqmp_ts)) {
186    /* Use the interrupt controller timestamp counter if available */
187    tc->tc_get_timecount = _SPARC_Get_timecount_up;
188    tc->tc_frequency = ambapp_freq_get(&ambapp_plb, LEON3_Timer_Adev);
189
190    leon3_tc_tick = leon3_tc_tick_irqmp_timestamp_init;
191
192    /*
193     * At least one TSISEL field must be non-zero to enable the timestamp
194     * counter.  Use an arbitrary interrupt source.
195     */
196    irqmp_ts->control = 0x1;
197  } else {
198#ifdef RTEMS_SMP
199    /*
200     * The GR712RC for example has no timestamp unit in the interrupt
201     * controller.  At least on SMP configurations we must use a second timer
202     * in free running mode for the timecounter.
203     */
204    gpt->timer[LEON3_COUNTER_GPTIMER_INDEX].ctrl =
205      GPTIMER_TIMER_CTRL_EN | GPTIMER_TIMER_CTRL_IE;
206
207    tc->tc_get_timecount = _SPARC_Get_timecount_down;
208#else
209    SPARC_Counter *counter;
210
211    counter = &_SPARC_Counter_mutable;
212    counter->read_isr_disabled = _SPARC_Counter_read_clock_isr_disabled;
213    counter->read = _SPARC_Counter_read_clock;
214    counter->counter_register = &gpt->timer[LEON3_CLOCK_INDEX].value;
215    counter->pending_register = &LEON3_IrqCtrl_Regs->ipend;
216    counter->pending_mask = UINT32_C(1) << clkirq;
217    counter->accumulated = rtems_configuration_get_microseconds_per_tick();
218    counter->interval = rtems_configuration_get_microseconds_per_tick();
219
220    tc->tc_get_timecount = _SPARC_Get_timecount_clock;
221#endif
222
223    tc->tc_frequency = LEON3_GPTIMER_0_FREQUENCY_SET_BY_BOOT_LOADER,
224    leon3_tc_tick = leon3_tc_tick_default;
225  }
226
227  tc->tc_counter_mask = 0xffffffff;
228  tc->tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER;
229  rtems_timecounter_install(tc);
230}
231
232#define Clock_driver_support_initialize_hardware() \
233  leon3_clock_initialize()
234
235#define Clock_driver_timecounter_tick() leon3_tc_do_tick()
236
237#include "../../../shared/dev/clock/clockimpl.h"
238
239#endif
Note: See TracBrowser for help on using the repository browser.