source: rtems/bsps/riscv/riscv/clock/clockdrv.c @ 6136e28b

Last change on this file since 6136e28b was 6136e28b, checked in by Sebastian Huber <sebastian.huber@…>, on 01/23/23 at 14:26:10

clockdrv: Add clock driver implementation group

Use standard wording in Clock Driver related files.

Update #3706.

  • Property mode set to 100644
File size: 6.7 KB
Line 
1/**
2 * @file
3 *
4 * @ingroup RTEMSDriverClockImpl
5 *
6 * @brief This source file contains the implementation of the riscv Clock
7 *   Driver.
8 */
9
10/*
11 * Copyright (c) 2018 embedded brains GmbH
12 * COPYRIGHT (c) 2015 Hesham Alatary <hesham@alumni.york.ac.uk>
13 *
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions
16 * are met:
17 * 1. Redistributions of source code must retain the above copyright
18 *    notice, this list of conditions and the following disclaimer.
19 * 2. Redistributions in binary form must reproduce the above copyright
20 *    notice, this list of conditions and the following disclaimer in the
21 *    documentation and/or other materials provided with the distribution.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36#include <bsp/fatal.h>
37#include <bsp/fdt.h>
38#include <bsp/irq.h>
39#include <bsp/riscv.h>
40
41#include <rtems/sysinit.h>
42#include <rtems/timecounter.h>
43#include <rtems/score/cpuimpl.h>
44#include <rtems/score/riscv-utility.h>
45#include <rtems/score/smpimpl.h>
46
47#include <libfdt.h>
48
49/* This is defined in dev/clock/clockimpl.h */
50void Clock_isr(void *arg);
51
52typedef struct {
53  struct timecounter base;
54  volatile RISCV_CLINT_regs *clint;
55  uint32_t interval;
56} riscv_timecounter;
57
58static riscv_timecounter riscv_clock_tc;
59
60static void riscv_clock_write_mtimecmp(
61  volatile RISCV_CLINT_timer_reg *mtimecmp,
62  uint64_t value
63)
64{
65#if __riscv_xlen == 32
66  mtimecmp->val_32[0] = 0xffffffff;
67  mtimecmp->val_32[1] = (uint32_t) (value >> 32);
68  mtimecmp->val_32[0] = (uint32_t) value;
69#elif __riscv_xlen == 64
70  mtimecmp->val_64 = value;
71#endif
72}
73
74static uint64_t riscv_clock_read_mtime(volatile RISCV_CLINT_timer_reg *mtime)
75{
76#if __riscv_xlen == 32
77  uint32_t low;
78  uint32_t high_0;
79  uint32_t high_1;
80
81  do {
82    high_0 = mtime->val_32[1];
83    low = mtime->val_32[0];
84    high_1 = mtime->val_32[1];
85  } while (high_0 != high_1);
86
87  return (((uint64_t) high_0) << 32) | low;
88#elif __riscv_xlen == 64
89  return mtime->val_64;
90#endif
91}
92
93static void riscv_clock_at_tick(riscv_timecounter *tc)
94{
95  volatile RISCV_CLINT_regs *clint;
96  uint64_t value;
97  uint32_t cpu = rtems_scheduler_get_processor();
98
99  cpu = _RISCV_Map_cpu_index_to_hardid(cpu);
100
101  clint = tc->clint;
102
103  value = clint->mtimecmp[cpu].val_64;
104  value += tc->interval;
105
106  riscv_clock_write_mtimecmp(&clint->mtimecmp[cpu], value);
107}
108
109static void riscv_clock_handler_install(void)
110{
111  rtems_status_code sc;
112
113  sc = rtems_interrupt_handler_install(
114    RISCV_INTERRUPT_VECTOR_TIMER,
115    "Clock",
116    RTEMS_INTERRUPT_UNIQUE,
117    (rtems_interrupt_handler) Clock_isr,
118    NULL
119  );
120  if (sc != RTEMS_SUCCESSFUL) {
121    bsp_fatal(RISCV_FATAL_CLOCK_IRQ_INSTALL);
122  }
123}
124
125static uint32_t riscv_clock_get_timecount(struct timecounter *base)
126{
127  riscv_timecounter *tc;
128  volatile RISCV_CLINT_regs *clint;
129
130  tc = (riscv_timecounter *) base;
131  clint = tc->clint;
132  return clint->mtime.val_32[0];
133}
134
135static uint32_t riscv_clock_get_timebase_frequency(const void *fdt)
136{
137  int node;
138  const fdt32_t *val;
139  int len=0;
140
141  node = fdt_path_offset(fdt, "/cpus");
142
143  val = (fdt32_t *) fdt_getprop(fdt, node, "timebase-frequency", &len);
144
145  if (val == NULL || len < 4) {
146    int cpu0 = fdt_subnode_offset(fdt, node, "cpu@0");
147    val = (fdt32_t *) fdt_getprop(fdt, cpu0, "timebase-frequency", &len);
148
149    if (val == NULL || len < 4) {
150      bsp_fatal(RISCV_FATAL_NO_TIMEBASE_FREQUENCY_IN_DEVICE_TREE);
151    }
152  }
153  return fdt32_to_cpu(*val);
154}
155
156static void riscv_clock_clint_init(
157  volatile RISCV_CLINT_regs *clint,
158  uint64_t cmpval,
159  uint32_t cpu
160)
161{
162  riscv_clock_write_mtimecmp(
163    &clint->mtimecmp[cpu],
164        cmpval
165  );
166
167  /* Enable mtimer interrupts */
168  set_csr(mie, MIP_MTIP);
169}
170
171#if defined(RTEMS_SMP) && !defined(CLOCK_DRIVER_USE_ONLY_BOOT_PROCESSOR)
172static void riscv_clock_secondary_action(void *arg)
173{
174  volatile RISCV_CLINT_regs *clint = riscv_clint;
175  uint64_t *cmpval = arg;
176  uint32_t cpu = _CPU_SMP_Get_current_processor();
177
178  cpu = _RISCV_Map_cpu_index_to_hardid(cpu);
179
180  riscv_clock_clint_init(clint, *cmpval, cpu);
181}
182#endif
183
184static void riscv_clock_secondary_initialization(
185  volatile RISCV_CLINT_regs *clint,
186  uint64_t cmpval,
187  uint32_t interval
188)
189{
190#if defined(RTEMS_SMP) && !defined(CLOCK_DRIVER_USE_ONLY_BOOT_PROCESSOR)
191  _SMP_Othercast_action(riscv_clock_secondary_action, &cmpval);
192
193  if (cmpval - riscv_clock_read_mtime(&clint->mtime) >= interval) {
194    bsp_fatal(RISCV_FATAL_CLOCK_SMP_INIT);
195  }
196#endif
197}
198
199static void riscv_clock_initialize(void)
200{
201  const char *fdt;
202  riscv_timecounter *tc;
203  volatile RISCV_CLINT_regs *clint;
204  uint32_t tb_freq;
205  uint64_t us_per_tick;
206  uint32_t interval;
207  uint64_t cmpval;
208
209  fdt = bsp_fdt_get();
210  tb_freq = riscv_clock_get_timebase_frequency(fdt);
211  us_per_tick = rtems_configuration_get_microseconds_per_tick();
212  interval = (uint32_t) ((tb_freq * us_per_tick) / 1000000);
213  clint = riscv_clint;
214  tc = &riscv_clock_tc;
215
216  tc->clint = clint;
217  tc->interval = interval;
218
219  cmpval = riscv_clock_read_mtime(&clint->mtime);
220  cmpval += interval;
221
222  riscv_clock_clint_init(clint, cmpval, RISCV_BOOT_HARTID);
223  riscv_clock_secondary_initialization(clint, cmpval, interval);
224
225  /* Initialize timecounter */
226  tc->base.tc_get_timecount = riscv_clock_get_timecount;
227  tc->base.tc_counter_mask = 0xffffffff;
228  tc->base.tc_frequency = tb_freq;
229  tc->base.tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER;
230  rtems_timecounter_install(&tc->base);
231}
232
233volatile uint32_t _RISCV_Counter_register;
234
235static void riscv_counter_initialize(void)
236{
237  _RISCV_Counter_mutable = &riscv_clint->mtime.val_32[0];
238}
239
240uint32_t _CPU_Counter_frequency( void )
241{
242  return riscv_clock_get_timebase_frequency(bsp_fdt_get());
243}
244
245CPU_Counter_ticks _CPU_Counter_read( void )
246{
247  return *_RISCV_Counter;
248}
249
250RTEMS_SYSINIT_ITEM(
251  riscv_counter_initialize,
252  RTEMS_SYSINIT_CPU_COUNTER,
253  RTEMS_SYSINIT_ORDER_FIRST
254);
255
256#define Clock_driver_support_at_tick() riscv_clock_at_tick(&riscv_clock_tc)
257
258#define Clock_driver_support_initialize_hardware() riscv_clock_initialize()
259
260#define Clock_driver_support_install_isr(isr) \
261  riscv_clock_handler_install()
262
263#include "../../../shared/dev/clock/clockimpl.h"
Note: See TracBrowser for help on using the repository browser.