riscv_platform_timer.h
Go to the documentation of this file.
1#ifndef _HARDWARE_RISCV_PLATFORM_TIMER_
2#define _HARDWARE_RISCV_PLATFORM_TIMER_
3
4#ifdef __cplusplus
5extern "C" {
6#endif
7
8#include "pico.h"
9#include "hardware/structs/sio.h"
10
33static inline void riscv_timer_set_enabled(bool enabled) {
34 if (enabled) {
35 // Note atomic rwtype is not supported on SIO
36 sio_hw->mtime_ctrl |= SIO_MTIME_CTRL_EN_BITS;
37 } else {
38 sio_hw->mtime_ctrl &= ~SIO_MTIME_CTRL_EN_BITS;
39 }
40}
41
49static inline void riscv_timer_set_fullspeed(bool fullspeed) {
50 if (fullspeed) {
51 sio_hw->mtime_ctrl |= SIO_MTIME_CTRL_FULLSPEED_BITS;
52 } else {
53 sio_hw->mtime_ctrl &= ~SIO_MTIME_CTRL_FULLSPEED_BITS;
54 }
55}
56
62static inline uint64_t riscv_timer_get_mtime(void) {
63 // Read procedure from RISC-V ISA manual to avoid being off by 2**32 on
64 // low half rollover -- note this loop generally executes only once, and
65 // should never execute more than twice:
66 uint32_t h0, l, h1;
67 do {
68 h0 = sio_hw->mtimeh;
69 l = sio_hw->mtime;
70 h1 = sio_hw->mtimeh;
71 } while (h0 != h1);
72 return l | (uint64_t)h1 << 32;
73}
74
85static inline void riscv_timer_set_mtime(uint64_t mtime) {
86 // This ought really only be done when the timer is stopped, but we can
87 // make things a bit safer by clearing the low half of the counter, then
88 // writing high half, then low half. This protects against the low half
89 // rolling over, and largely avoids getting an intermediate value that is
90 // higher than either the original or new value, if the timer is running.
91 //
92 // Note that on RP2350, mtime is shared between the two cores!(mtimcemp is
93 // core-local however.)
94 sio_hw->mtime = 0;
95 sio_hw->mtimeh = mtime >> 32;
96 sio_hw->mtime = mtime & 0xffffffffu;
97}
98
108static inline uint64_t riscv_timer_get_mtimecmp(void) {
109 // Use the same procedure as reading mtime, which should be safe assuming
110 // mtimecmp increases monotonically with successive interrupts.
111 uint32_t h0, l, h1;
112 do {
113 h0 = sio_hw->mtimecmph;
114 l = sio_hw->mtimecmp;
115 h1 = sio_hw->mtimecmph;
116 } while (h0 != h1);
117 return l | (uint64_t)h1 << 32;
118}
119
130static inline void riscv_timer_set_mtimecmp(uint64_t mtimecmp) {
131 // Use write procedure from RISC-V ISA manual to avoid causing a spurious
132 // interrupt when updating the two halves of mtimecmp.
133 // No lower than original:
134 sio_hw->mtimecmp = -1u;
135 // No lower than original, no lower than new (assuming new >= original):
136 sio_hw->mtimecmph = mtimecmp >> 32;
137 // Equal to new:
138 sio_hw->mtimecmp = mtimecmp & 0xffffffffu;
139}
140
141#ifdef __cplusplus
142}
143#endif
144
145#endif
static uint64_t riscv_timer_get_mtimecmp(void)
Get the current RISC-V platform timer mtimecmp value for this core.
Definition: riscv_platform_timer.h:108
static void riscv_timer_set_enabled(bool enabled)
Enable or disable the RISC-V platform timer.
Definition: riscv_platform_timer.h:33
static void riscv_timer_set_mtimecmp(uint64_t mtimecmp)
Set a new RISC-V platform timer interrupt comparison value (mtimecmp) for this core.
Definition: riscv_platform_timer.h:130
static void riscv_timer_set_mtime(uint64_t mtime)
Update the RISC-V platform timer.
Definition: riscv_platform_timer.h:85
static uint64_t riscv_timer_get_mtime(void)
Read the RISC-V platform timer.
Definition: riscv_platform_timer.h:62
static void riscv_timer_set_fullspeed(bool fullspeed)
Configure the RISC-V platform timer to run at full system clock speed.
Definition: riscv_platform_timer.h:49