1 /*
2  * Copyright (c) 2018 - 2024, Nordic Semiconductor ASA
3  * All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright notice, this
11  *    list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * 3. Neither the name of the copyright holder nor the names of its
18  *    contributors may be used to endorse or promote products derived from this
19  *    software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
25  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31  * POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #ifndef NRFX_COREDEP_H__
35 #define NRFX_COREDEP_H__
36 
37 #include <nrfx.h>
38 #if NRFX_CHECK(ISA_RISCV)
39 #include <hal/nrf_vpr_csr.h>
40 #include <hal/nrf_vpr_csr_vtim.h>
41 #endif
42 
43 /**
44  * @defgroup nrfx_coredep Core-dependent functionality
45  * @{
46  * @ingroup nrfx
47  * @brief Module containing functions with core-dependent implementation, like delay.
48  */
49 
50 #if defined(__NRFX_DOXYGEN__)
51 
52 /** @brief Core frequency (in MHz). */
53 #define NRFX_DELAY_CPU_FREQ_MHZ
54 /** @brief Availability of Data Watchpoint and Trace (DWT) unit in the given SoC. */
55 #define NRFX_DELAY_DWT_PRESENT
56 /**
57  * @brief Number of cycles consumed by one iteration of the internal loop
58  *        in the function @ref nrfx_coredep_delay_us.
59  *
60  * This value can be specified externally (for example, when the SoC is emulated).
61  */
62 #define NRFX_COREDEP_DELAY_US_LOOP_CYCLES
63 
64 #elif defined(NRFX_DELAY_CPU_FREQ_MHZ) && defined(NRFX_DELAY_DWT_PRESENT)
65     /* Do nothing. */
66 #elif defined(NRF51)
67     #define NRFX_DELAY_CPU_FREQ_MHZ 16
68     #define NRFX_DELAY_DWT_PRESENT  0
69 #elif defined(NRF52805_XXAA) || defined(NRF52810_XXAA) || \
70       defined(NRF52811_XXAA) || defined(NRF52820_XXAA)
71     #define NRFX_DELAY_CPU_FREQ_MHZ 64
72     #define NRFX_DELAY_DWT_PRESENT  0
73 #elif defined(NRF52832_XXAA) || defined(NRF52832_XXAB) || \
74       defined(NRF52833_XXAA) || defined(NRF52840_XXAA) || \
75       defined(NRF9120_XXAA)  || defined(NRF9160_XXAA)
76     #define NRFX_DELAY_CPU_FREQ_MHZ 64
77     #define NRFX_DELAY_DWT_PRESENT  1
78 #elif defined(NRF5340_XXAA_APPLICATION)
79     #define NRFX_DELAY_CPU_FREQ_MHZ (SystemCoreClock / 1000000)
80     #define NRFX_DELAY_DWT_PRESENT  1
81 #elif defined(NRF5340_XXAA_NETWORK)
82     #define NRFX_DELAY_CPU_FREQ_MHZ 64
83     #define NRFX_DELAY_DWT_PRESENT  1
84 #elif defined(NRF54H20_XXAA) || defined(NRF54H20_ENGA_XXAA)
85     #define NRFX_DELAY_CPU_FREQ_MHZ (SystemCoreClock / 1000000)
86     #define NRFX_DELAY_DWT_PRESENT  0
87 #elif defined(NRF54L15_XXAA) || defined(NRF54L15_ENGA_XXAA)
88     #define NRFX_DELAY_CPU_FREQ_MHZ (SystemCoreClock / 1000000)
89     #define NRFX_DELAY_DWT_PRESENT  1
90 #else
91     #error "Unknown device"
92 #endif
93 
94 /**
95  * @brief Function for delaying execution for a number of microseconds.
96  *
97  * The value of @p time_us is multiplied by the CPU frequency in MHz. Therefore, the delay
98  * is limited to the maximum value of the uint32_t type divided by the frequency.
99  * @sa NRFX_COREDEP_DELAY_US_LOOP_CYCLES
100  *
101  * @param time_us Number of microseconds to wait.
102  */
103 NRF_STATIC_INLINE void nrfx_coredep_delay_us(uint32_t time_us);
104 
105 /** @} */
106 
107 #ifndef NRF_DECLARE_ONLY
108 
109 #if NRFX_CHECK(NRFX_DELAY_DWT_BASED)
110 
111 #if !NRFX_DELAY_DWT_PRESENT
112 #error "DWT unit not present in the SoC that is used."
113 #endif
114 
nrfx_coredep_delay_us(uint32_t time_us)115 NRF_STATIC_INLINE void nrfx_coredep_delay_us(uint32_t time_us)
116 {
117     if (time_us == 0)
118     {
119         return;
120     }
121     uint32_t time_cycles = time_us * NRFX_DELAY_CPU_FREQ_MHZ;
122 
123     // Save the current state of the DEMCR register to be able to restore it before exiting
124     // this function. Enable the trace and debug blocks (including DWT).
125     uint32_t core_debug = CoreDebug->DEMCR;
126     CoreDebug->DEMCR = core_debug | CoreDebug_DEMCR_TRCENA_Msk;
127 
128     // Save the current state of the CTRL register in the DWT block. Make sure
129     // that the cycle counter is enabled.
130     uint32_t dwt_ctrl = DWT->CTRL;
131     DWT->CTRL = dwt_ctrl | DWT_CTRL_CYCCNTENA_Msk;
132 
133     // Store start value of the cycle counter.
134     uint32_t cyccnt_initial = DWT->CYCCNT;
135 
136     // Delay required time.
137     while ((DWT->CYCCNT - cyccnt_initial) < time_cycles)
138     {}
139 
140     // Restore preserved registers.
141     DWT->CTRL = dwt_ctrl;
142     CoreDebug->DEMCR = core_debug;
143 }
144 
145 #else // NRFX_CHECK(NRFX_DELAY_DWT_BASED)
146 
nrfx_coredep_delay_us(uint32_t time_us)147 NRF_STATIC_INLINE void nrfx_coredep_delay_us(uint32_t time_us)
148 {
149     if (time_us == 0)
150     {
151         return;
152     }
153 
154 #if NRFX_CHECK(ISA_ARM)
155     // Allow overriding the number of cycles per loop iteration, in case it is
156     // needed to adjust this number externally (for example, when the SoC is
157     // emulated).
158     #ifndef NRFX_COREDEP_DELAY_US_LOOP_CYCLES
159         #if defined(NRF51)
160             // The loop takes 4 cycles: 1 for SUBS, 3 for BHI.
161             #define NRFX_COREDEP_DELAY_US_LOOP_CYCLES  4
162         #elif defined(NRF52805_XXAA) || defined(NRF52810_XXAA) || \
163               defined(NRF52811_XXAA) || defined(NRF52820_XXAA)
164             // The loop takes 7 cycles: 1 for SUBS, 2 for BHI, 2 wait states
165             // for each instruction.
166             #define NRFX_COREDEP_DELAY_US_LOOP_CYCLES  7
167         #else
168             // The loop takes 3 cycles: 1 for SUBS, 2 for BHI.
169             #define NRFX_COREDEP_DELAY_US_LOOP_CYCLES  3
170         #endif
171     #endif // NRFX_COREDEP_DELAY_US_LOOP_CYCLES
172     // Align the machine code, so that it can be cached properly and no extra
173     // wait states appear.
174     __ALIGN(16)
175     static const uint16_t delay_machine_code[] = {
176         0x3800 + NRFX_COREDEP_DELAY_US_LOOP_CYCLES, // SUBS r0, #loop_cycles
177         0xd8fd, // BHI .-2
178         0x4770  // BX LR
179     };
180 
181     typedef void (* delay_func_t)(uint32_t);
182     const delay_func_t delay_cycles =
183         // Set LSB to 1 to execute the code in the Thumb mode.
184         (delay_func_t)((((uint32_t)delay_machine_code) | 1));
185     uint32_t cycles = time_us * NRFX_DELAY_CPU_FREQ_MHZ;
186     delay_cycles(cycles);
187 #elif NRFX_CHECK(ISA_RISCV)
188 #if !NRFX_CHECK(NRFX_COREDEP_VPR_LEGACY)
189     nrf_vpr_csr_vtim_count_mode_set(1, NRF_VPR_CSR_VTIM_COUNT_TRIGGER_COMBINED);
190     nrf_vpr_csr_vtim_combined_counter_set(time_us * NRFX_DELAY_CPU_FREQ_MHZ);
191     nrf_vpr_csr_vtim_combined_wait_trigger();
192 #else
193     #if !defined(NRFX_DELAY_RISCV_SLOWDOWN)
194         #if defined(NRF54L15_XXAA) || defined(NRF54L15_ENGA_XXAA)
195             #define NRFX_DELAY_RISCV_SLOWDOWN 15
196         #else
197             #define NRFX_DELAY_RISCV_SLOWDOWN 50
198         #endif // defined(NRF54L15_XXAA) || defined(NRF54L15_ENGA_XXAA)
199     #endif // !defined(NRFX_DELAY_RISCV_SLOWDOWN)
200 
201     for (volatile uint32_t i = 0;
202              i < ((NRFX_DELAY_CPU_FREQ_MHZ * time_us) / NRFX_DELAY_RISCV_SLOWDOWN);
203              i++)
204         {}
205 
206 #endif // !NRFX_CHECK(NRFX_CONFIG_COREDEP_VPR_LEGACY)
207 #endif // NRFX_CHECK(ISA_ARM)
208 }
209 
210 #endif // !NRFX_CHECK(NRFX_DELAY_DWT_BASED_DELAY)
211 
212 #endif // NRF_DECLARE_ONLY
213 
214 #endif // NRFX_COREDEP_H__
215