-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtimer.c
More file actions
57 lines (50 loc) · 2.12 KB
/
timer.c
File metadata and controls
57 lines (50 loc) · 2.12 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
/*
Simple machine mode timer driver for RISC-V standard timer.
SPDX-License-Identifier: Unlicense
(https://five-embeddev.com/)
*/
#include "timer.h"
// NOLINTBEGIN (performance-no-int-to-ptr)
// performance-no-int-to-ptr: MMIO Address represented as integer is converted to pointer.
void mtimer_set_raw_time_cmp(uint64_t clock_offset) {
// First of all set
uint64_t new_mtimecmp = mtimer_get_raw_time() + clock_offset;
#if (__riscv_xlen == 64)
// Single bus access
volatile uint64_t* const mtimecmp = (volatile uint64_t*)(RISCV_MTIMECMP_ADDR);
*mtimecmp = new_mtimecmp;
#else
volatile uint32_t* const mtimecmpl = (volatile uint32_t*)(RISCV_MTIMECMP_ADDR);
volatile uint32_t* const mtimecmph = (volatile uint32_t*)(RISCV_MTIMECMP_ADDR + 4);
// AS we are doing 32 bit writes, an intermediate mtimecmp value may cause spurious interrupts.
// Prevent that by first setting the dummy MSB to an unacheivable value
*mtimecmph = 0xFFFFFFFFUL;// cppcheck-suppress redundantAssignment
// set the LSB
*mtimecmpl = (uint32_t)(new_mtimecmp & 0x0FFFFFFFFUL);
// Set the correct MSB
*mtimecmph = (uint32_t)(new_mtimecmp >> 32UL);// cppcheck-suppress redundantAssignment
#endif
}
/** Read the raw time of the system timer in system timer clocks
*/
uint64_t mtimer_get_raw_time(void) {
#if (__riscv_xlen == 64)
// Directly read 64 bit value
volatile const uint64_t* const mtime = (volatile uint64_t*)(RISCV_MTIME_ADDR);
return *mtime;
#else
volatile const uint32_t* const mtimel = (volatile uint32_t*)(RISCV_MTIME_ADDR);
volatile const uint32_t* const mtimeh = (volatile uint32_t*)(RISCV_MTIME_ADDR + 4);
uint32_t mtimeh_val = 0;
uint32_t mtimel_val = 0;
do {
// There is a small risk the mtimeh will tick over after reading mtimel
mtimeh_val = *mtimeh;
mtimel_val = *mtimel;
// Poll mtimeh to ensure it's consistent after reading mtimel
// The frequency of mtimeh ticking over is low
} while (mtimeh_val != *mtimeh);
return (uint64_t)((((uint64_t)mtimeh_val) << 32UL) | mtimel_val);
#endif
}
// NOLINTEND (performance-no-int-to-ptr)