source: rtems/bsps/riscv/griscv/clock/clockdrv.c @ d3d4e77

5
Last change on this file since d3d4e77 was d3d4e77, checked in by Jiri Gaisler <jiri@…>, on 01/18/19 at 11:37:55

riscv: add griscv bsp

Update #3678.

  • Property mode set to 100644
File size: 4.9 KB
Line 
1/*
2 *  Clock Tick Device Driver
3 *
4 *  This routine initializes GRLIB gptimer 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 GRLIB 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 <amba.h>
25#include <bsp/irq.h>
26#include <bspopts.h>
27#include <bsp/fatal.h>
28#include <rtems/rtems/intr.h>
29#include <grlib/ambapp.h>
30#include <rtems/score/profiling.h>
31#include <rtems/timecounter.h>
32#include <rtems/score/cpuimpl.h>
33#include <rtems/score/riscv-utility.h>
34
35volatile uint32_t _RISCV_Counter_register;
36
37/* The GRLIB BSP Timer driver can rely on the Driver Manager if the
38 * DrvMgr is initialized during startup. Otherwise the classic driver
39 * must be used.
40 *
41 * The DrvMgr Clock driver is located in the shared/timer directory
42 */
43#ifndef RTEMS_DRVMGR_STARTUP
44
45/* GRLIB Timer system interrupt number */
46static int clkirq;
47
48static void (*grlib_tc_tick)(void);
49
50static struct timecounter grlib_tc;
51
52#ifdef RTEMS_PROFILING
53#define IRQMP_TIMESTAMP_S1_S2 ((1U << 25) | (1U << 26))
54
55static void grlib_tc_tick_irqmp_timestamp(void)
56{
57  volatile struct irqmp_timestamp_regs *irqmp_ts =
58    &GRLIB_IrqCtrl_Regs->timestamp[0];
59  unsigned int first = irqmp_ts->assertion;
60  unsigned int second = irqmp_ts->counter;
61
62  irqmp_ts->control |= IRQMP_TIMESTAMP_S1_S2;
63
64  _Profiling_Update_max_interrupt_delay(_Per_CPU_Get(), second - first);
65
66  rtems_timecounter_tick();
67}
68#endif
69
70static void grlib_tc_tick_irqmp_timestamp_init(void)
71{
72#ifdef RTEMS_PROFILING
73  /*
74   * Ignore the first clock interrupt, since it contains the sequential system
75   * initialization time.  Do the timestamp initialization on the fly.
76   */
77
78#ifdef RTEMS_SMP
79  static Atomic_Uint counter = ATOMIC_INITIALIZER_UINT(0);
80
81  bool done =
82    _Atomic_Fetch_add_uint(&counter, 1, ATOMIC_ORDER_RELAXED)
83      == rtems_get_processor_count() - 1;
84#else
85  bool done = true;
86#endif
87
88  volatile struct irqmp_timestamp_regs *irqmp_ts =
89    &GRLIB_IrqCtrl_Regs->timestamp[0];
90  unsigned int ks = 1U << 5;
91
92  irqmp_ts->control = ks | IRQMP_TIMESTAMP_S1_S2 | (unsigned int) clkirq;
93
94  if (done) {
95    grlib_tc_tick = grlib_tc_tick_irqmp_timestamp;
96  }
97#endif
98
99  rtems_timecounter_tick();
100}
101
102static void grlib_tc_do_tick(void)
103{
104  (*grlib_tc_tick)();
105}
106
107#define Adjust_clkirq_for_node() do { clkirq += GRLIB_CLOCK_INDEX; } while(0)
108
109#define Clock_driver_support_find_timer() \
110  do { \
111    /* Assume timer found during BSP initialization */ \
112    if (GRLIB_Timer_Regs) { \
113      clkirq = (GRLIB_Timer_Regs->cfg & 0xf8) >> 3; \
114      \
115      Adjust_clkirq_for_node(); \
116    } \
117  } while (0)
118
119#define Clock_driver_support_install_isr( _new ) \
120  bsp_clock_handler_install(_new)
121
122static void bsp_clock_handler_install(rtems_isr *new)
123{
124  rtems_status_code sc;
125
126  sc = rtems_interrupt_handler_install(
127    clkirq,
128    "Clock",
129    RTEMS_INTERRUPT_UNIQUE,
130    new,
131    NULL
132  );
133  if (sc != RTEMS_SUCCESSFUL) {
134    rtems_fatal(RTEMS_FATAL_SOURCE_BSP, LEON3_FATAL_CLOCK_INITIALIZATION);
135  }
136}
137
138#define Clock_driver_support_set_interrupt_affinity(online_processors) \
139  bsp_interrupt_set_affinity(clkirq, online_processors)
140
141uint32_t _CPU_Counter_frequency( void )
142{
143  return grlib_up_counter_frequency();
144}
145
146
147static uint32_t _RISCV_Get_timecount_csr(struct timecounter *tc)
148{
149  return read_csr(time);
150}
151
152static void grlib_clock_initialize(void)
153{
154  volatile struct gptimer_regs *gpt;
155  struct timecounter *tc;
156
157  gpt = GRLIB_Timer_Regs;
158  tc = &grlib_tc;
159
160  gpt->timer[GRLIB_CLOCK_INDEX].reload =
161    rtems_configuration_get_microseconds_per_tick() - 1;
162  gpt->timer[GRLIB_CLOCK_INDEX].ctrl =
163    GPTIMER_TIMER_CTRL_EN | GPTIMER_TIMER_CTRL_RS |
164      GPTIMER_TIMER_CTRL_LD | GPTIMER_TIMER_CTRL_IE;
165
166    /* Use the RISCV time register as up-counter */
167  tc->tc_get_timecount = _RISCV_Get_timecount_csr;
168  tc->tc_frequency = grlib_up_counter_frequency();
169
170#ifdef RTEMS_PROFILING
171  volatile struct irqmp_timestamp_regs *irqmp_ts =
172    &GRLIB_IrqCtrl_Regs->timestamp[0];
173
174    if (!grlib_irqmp_has_timestamp(irqmp_ts)) {
175      bsp_fatal(GRLIB_FATAL_CLOCK_NO_IRQMP_TIMESTAMP_SUPPORT);
176    }
177#endif
178
179  grlib_tc_tick = grlib_tc_tick_irqmp_timestamp_init;
180
181  tc->tc_counter_mask = 0xffffffff;
182  tc->tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER;
183  rtems_timecounter_install(tc);
184}
185
186CPU_Counter_ticks _CPU_Counter_read( void )
187{
188  unsigned long timec;
189
190  __asm__ volatile ( "csrr %0, time" : "=&r" ( timec ) );
191
192  return timec;
193}
194
195#define Clock_driver_support_initialize_hardware() \
196  grlib_clock_initialize()
197
198#define Clock_driver_timecounter_tick() grlib_tc_do_tick()
199
200#include "../../../shared/dev/clock/clockimpl.h"
201
202#endif
Note: See TracBrowser for help on using the repository browser.