source: rtems/bsps/riscv/riscv/clock/clockdrv.c @ 48cbd63

5
Last change on this file since 48cbd63 was 48cbd63, checked in by Sebastian Huber <sebastian.huber@…>, on 07/31/18 at 05:19:33

bsp/riscv: Fix clock driver

Do not assume that mtime is zero at boot time.

Update #3433.

  • Property mode set to 100644
File size: 5.3 KB
Line 
1/**
2 * @file
3 *
4 * @ingroup bsp_clock
5 *
6 * @brief riscv clock support.
7 */
8
9/*
10 * Copyright (c) 2018 embedded brains GmbH
11 * COPYRIGHT (c) 2015 Hesham Alatary <hesham@alumni.york.ac.uk>
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
15 * are met:
16 * 1. Redistributions of source code must retain the above copyright
17 *    notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 *    notice, this list of conditions and the following disclaimer in the
20 *    documentation and/or other materials provided with the distribution.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35#include <bsp/fatal.h>
36#include <bsp/fdt.h>
37#include <bsp/irq.h>
38#include <bsp/riscv.h>
39
40#include <rtems/sysinit.h>
41#include <rtems/timecounter.h>
42#include <rtems/score/cpuimpl.h>
43#include <rtems/score/riscv-utility.h>
44
45#include <libfdt.h>
46
47/* This is defined in dev/clock/clockimpl.h */
48void Clock_isr(void *arg);
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  volatile RISCV_CLINT_regs *clint;
94  uint64_t value;
95
96  clint = tc->clint;
97
98  value = clint->mtimecmp[0].val_64;
99  value += tc->interval;
100
101  riscv_clock_write_mtimecmp(&clint->mtimecmp[0], value);
102}
103
104static void riscv_clock_handler_install(void)
105{
106  rtems_status_code sc;
107
108  sc = rtems_interrupt_handler_install(
109    RISCV_INTERRUPT_VECTOR_TIMER,
110    "Clock",
111    RTEMS_INTERRUPT_UNIQUE,
112    (rtems_interrupt_handler) Clock_isr,
113    NULL
114  );
115  if (sc != RTEMS_SUCCESSFUL) {
116    bsp_fatal(RISCV_FATAL_CLOCK_IRQ_INSTALL);
117  }
118}
119
120static uint32_t riscv_clock_get_timecount(struct timecounter *base)
121{
122  riscv_timecounter *tc;
123  volatile RISCV_CLINT_regs *clint;
124
125  tc = (riscv_timecounter *) base;
126  clint = tc->clint;
127  return clint->mtime.val_32[0];
128}
129
130static uint32_t riscv_clock_get_timebase_frequency(const void *fdt)
131{
132  int node;
133  const uint32_t *val;
134  int len;
135
136  node = fdt_path_offset(fdt, "/cpus");
137  val = fdt_getprop(fdt, node, "timebase-frequency", &len);
138  if (val == NULL || len < 4) {
139    bsp_fatal(RISCV_FATAL_NO_TIMEBASE_FREQUENCY_IN_DEVICE_TREE);
140  }
141
142  return fdt32_to_cpu(*val);
143}
144
145static void riscv_clock_initialize(void)
146{
147  const char *fdt;
148  riscv_timecounter *tc;
149  volatile RISCV_CLINT_regs *clint;
150  uint32_t tb_freq;
151  uint64_t us_per_tick;
152  uint32_t interval;
153
154  fdt = bsp_fdt_get();
155  tb_freq = riscv_clock_get_timebase_frequency(fdt);
156  us_per_tick = rtems_configuration_get_microseconds_per_tick();
157  interval = (uint32_t) ((tb_freq * us_per_tick) / 1000000);
158  clint = riscv_clint;
159  tc = &riscv_clock_tc;
160
161  tc->clint = clint;
162  tc->interval = interval;
163
164  riscv_clock_write_mtimecmp(
165    &clint->mtimecmp[0],
166    riscv_clock_read_mtime(&clint->mtime) + interval
167  );
168
169  /* Enable mtimer interrupts */
170  set_csr(mie, MIP_MTIP);
171
172  /* Initialize timecounter */
173  tc->base.tc_get_timecount = riscv_clock_get_timecount;
174  tc->base.tc_counter_mask = 0xffffffff;
175  tc->base.tc_frequency = tb_freq;
176  tc->base.tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER;
177  rtems_timecounter_install(&tc->base);
178}
179
180volatile uint32_t _RISCV_Counter_register;
181
182static void riscv_counter_initialize(void)
183{
184  _RISCV_Counter_mutable = &riscv_clint->mtime.val_32[0];
185}
186
187uint32_t _CPU_Counter_frequency( void )
188{
189  return riscv_clock_get_timebase_frequency(bsp_fdt_get());
190}
191
192RTEMS_SYSINIT_ITEM(
193  riscv_counter_initialize,
194  RTEMS_SYSINIT_CPU_COUNTER,
195  RTEMS_SYSINIT_ORDER_FIRST
196);
197
198#define Clock_driver_support_at_tick() riscv_clock_at_tick(&riscv_clock_tc)
199
200#define Clock_driver_support_initialize_hardware() riscv_clock_initialize()
201
202#define Clock_driver_support_install_isr(isr) \
203  riscv_clock_handler_install()
204
205#define CLOCK_DRIVER_USE_ONLY_BOOT_PROCESSOR
206
207#include "../../../shared/dev/clock/clockimpl.h"
Note: See TracBrowser for help on using the repository browser.