source: rtems/bsps/riscv/riscv/clock/clockdrv.c

Last change on this file was 1eed6f8, checked in by Sebastian Huber <sebastian.huber@…>, on 03/23/23 at 15:53:30

bsps: Avoid unused argument in clock interrupt

Pass the parameter of the clock interrupt handler to
Clock_driver_support_at_tick() and Clock_driver_timecounter_tick(). This makes
it possible to use the interrupt handler argument in clock drivers.

Use the interrupt handler provided by Clock_driver_support_install_isr() to
avoid local delarations of Clock_isr().

Update #4862.

  • Property mode set to 100644
File size: 6.5 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, 2023 embedded brains GmbH & Co. KG
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/percpu.h>
45#include <rtems/score/riscv-utility.h>
46#include <rtems/score/smpimpl.h>
47
48#include <libfdt.h>
49
50typedef struct {
51  struct timecounter base;
52  volatile RISCV_CLINT_regs *clint;
53  uint32_t interval;
54} riscv_timecounter;
55
56static riscv_timecounter riscv_clock_tc;
57
58static void riscv_clock_write_mtimecmp(
59  volatile RISCV_CLINT_timer_reg *mtimecmp,
60  uint64_t value
61)
62{
63#if __riscv_xlen == 32
64  mtimecmp->val_32[0] = 0xffffffff;
65  mtimecmp->val_32[1] = (uint32_t) (value >> 32);
66  mtimecmp->val_32[0] = (uint32_t) value;
67#elif __riscv_xlen == 64
68  mtimecmp->val_64 = value;
69#endif
70}
71
72static uint64_t riscv_clock_read_mtime(volatile RISCV_CLINT_timer_reg *mtime)
73{
74#if __riscv_xlen == 32
75  uint32_t low;
76  uint32_t high_0;
77  uint32_t high_1;
78
79  do {
80    high_0 = mtime->val_32[1];
81    low = mtime->val_32[0];
82    high_1 = mtime->val_32[1];
83  } while (high_0 != high_1);
84
85  return (((uint64_t) high_0) << 32) | low;
86#elif __riscv_xlen == 64
87  return mtime->val_64;
88#endif
89}
90
91static void riscv_clock_at_tick(riscv_timecounter *tc)
92{
93  Per_CPU_Control *cpu_self;
94  volatile RISCV_CLINT_timer_reg *mtimecmp;
95  uint64_t value;
96
97  cpu_self = _Per_CPU_Get();
98  mtimecmp = cpu_self->cpu_per_cpu.clint_mtimecmp;
99  value = mtimecmp->val_64;
100  value += tc->interval;
101
102  riscv_clock_write_mtimecmp(mtimecmp, value);
103}
104
105static void riscv_clock_handler_install(rtems_interrupt_handler handler)
106{
107  rtems_status_code sc;
108
109  sc = rtems_interrupt_handler_install(
110    RISCV_INTERRUPT_VECTOR_TIMER,
111    "Clock",
112    RTEMS_INTERRUPT_UNIQUE,
113    handler,
114    &riscv_clock_tc
115  );
116  if (sc != RTEMS_SUCCESSFUL) {
117    bsp_fatal(RISCV_FATAL_CLOCK_IRQ_INSTALL);
118  }
119}
120
121static uint32_t riscv_clock_get_timecount(struct timecounter *base)
122{
123  riscv_timecounter *tc;
124  volatile RISCV_CLINT_regs *clint;
125
126  tc = (riscv_timecounter *) base;
127  clint = tc->clint;
128  return clint->mtime.val_32[0];
129}
130
131static uint32_t riscv_clock_get_timebase_frequency(const void *fdt)
132{
133  int node;
134  const fdt32_t *val;
135  int len=0;
136
137  node = fdt_path_offset(fdt, "/cpus");
138
139  val = (fdt32_t *) fdt_getprop(fdt, node, "timebase-frequency", &len);
140
141  if (val == NULL || len < 4) {
142    int cpu0 = fdt_subnode_offset(fdt, node, "cpu@0");
143    val = (fdt32_t *) fdt_getprop(fdt, cpu0, "timebase-frequency", &len);
144
145    if (val == NULL || len < 4) {
146      bsp_fatal(RISCV_FATAL_NO_TIMEBASE_FREQUENCY_IN_DEVICE_TREE);
147    }
148  }
149  return fdt32_to_cpu(*val);
150}
151
152static void riscv_clock_clint_init(uint64_t cmpval)
153{
154  Per_CPU_Control *cpu_self;
155
156  cpu_self = _Per_CPU_Get();
157  riscv_clock_write_mtimecmp(cpu_self->cpu_per_cpu.clint_mtimecmp, cmpval);
158
159  /* Enable mtimer interrupts */
160  set_csr(mie, MIP_MTIP);
161}
162
163#if defined(RTEMS_SMP) && !defined(CLOCK_DRIVER_USE_ONLY_BOOT_PROCESSOR)
164static void riscv_clock_secondary_action(void *arg)
165{
166  riscv_clock_clint_init(*(uint64_t *) arg);
167}
168#endif
169
170static void riscv_clock_secondary_initialization(
171  volatile RISCV_CLINT_regs *clint,
172  uint64_t cmpval,
173  uint32_t interval
174)
175{
176#if defined(RTEMS_SMP) && !defined(CLOCK_DRIVER_USE_ONLY_BOOT_PROCESSOR)
177  _SMP_Othercast_action(riscv_clock_secondary_action, &cmpval);
178
179  if (cmpval - riscv_clock_read_mtime(&clint->mtime) >= interval) {
180    bsp_fatal(RISCV_FATAL_CLOCK_SMP_INIT);
181  }
182#endif
183}
184
185static void riscv_clock_initialize(void)
186{
187  const char *fdt;
188  riscv_timecounter *tc;
189  volatile RISCV_CLINT_regs *clint;
190  uint32_t tb_freq;
191  uint64_t us_per_tick;
192  uint32_t interval;
193  uint64_t cmpval;
194
195  fdt = bsp_fdt_get();
196  tb_freq = riscv_clock_get_timebase_frequency(fdt);
197  us_per_tick = rtems_configuration_get_microseconds_per_tick();
198  interval = (uint32_t) ((tb_freq * us_per_tick) / 1000000);
199  clint = riscv_clint;
200  tc = &riscv_clock_tc;
201
202  tc->clint = clint;
203  tc->interval = interval;
204
205  cmpval = riscv_clock_read_mtime(&clint->mtime);
206  cmpval += interval;
207
208  riscv_clock_clint_init(cmpval);
209  riscv_clock_secondary_initialization(clint, cmpval, interval);
210
211  /* Initialize timecounter */
212  tc->base.tc_get_timecount = riscv_clock_get_timecount;
213  tc->base.tc_counter_mask = 0xffffffff;
214  tc->base.tc_frequency = tb_freq;
215  tc->base.tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER;
216  rtems_timecounter_install(&tc->base);
217}
218
219volatile uint32_t _RISCV_Counter_register;
220
221static void riscv_counter_initialize(void)
222{
223  _RISCV_Counter_mutable = &riscv_clint->mtime.val_32[0];
224}
225
226uint32_t _CPU_Counter_frequency( void )
227{
228  return riscv_clock_get_timebase_frequency(bsp_fdt_get());
229}
230
231CPU_Counter_ticks _CPU_Counter_read( void )
232{
233  return *_RISCV_Counter;
234}
235
236RTEMS_SYSINIT_ITEM(
237  riscv_counter_initialize,
238  RTEMS_SYSINIT_CPU_COUNTER,
239  RTEMS_SYSINIT_ORDER_FIRST
240);
241
242#define Clock_driver_support_at_tick(arg) riscv_clock_at_tick(arg)
243
244#define Clock_driver_support_initialize_hardware() riscv_clock_initialize()
245
246#define Clock_driver_support_install_isr(isr) \
247  riscv_clock_handler_install(isr)
248
249#include "../../../shared/dev/clock/clockimpl.h"
Note: See TracBrowser for help on using the repository browser.