1 /*
2 * Copyright (c) 2023 STMicroelectronics
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/kernel.h>
8 #include <zephyr/drivers/entropy.h>
9 #include <zephyr/logging/log.h>
10
11 #include "scm.h"
12
13 #define LOG_LEVEL CONFIG_SOC_LOG_LEVEL
14 LOG_MODULE_REGISTER(linklayer_plat_adapt);
15
16 #define RADIO_INTR_PRIO_HIGH_Z (RADIO_INTR_PRIO_HIGH + _IRQ_PRIO_OFFSET)
17 #define RADIO_INTR_PRIO_LOW_Z (RADIO_INTR_PRIO_LOW + _IRQ_PRIO_OFFSET)
18
19 /* 2.4GHz RADIO ISR callbacks */
20 typedef void (*radio_isr_cb_t) (void);
21
22 radio_isr_cb_t radio_callback;
23 radio_isr_cb_t low_isr_callback;
24
25 extern const struct device *rng_dev;
26
27 /* Radio critical sections */
28 volatile int32_t prio_high_isr_counter;
29 volatile int32_t prio_low_isr_counter;
30 volatile int32_t prio_sys_isr_counter;
31 volatile uint32_t local_basepri_value;
32
33 /* Radio SW low ISR global variable */
34 volatile uint8_t radio_sw_low_isr_is_running_high_prio;
35
36
LINKLAYER_PLAT_DelayUs(uint32_t delay)37 void LINKLAYER_PLAT_DelayUs(uint32_t delay)
38 {
39 k_busy_wait(delay);
40 }
41
LINKLAYER_PLAT_GetRNG(uint8_t * ptr_rnd,uint32_t len)42 void LINKLAYER_PLAT_GetRNG(uint8_t *ptr_rnd, uint32_t len)
43 {
44 int ret;
45
46 /* Read 32-bit random values from HW driver */
47 ret = entropy_get_entropy_isr(rng_dev, (char *)ptr_rnd, len, 0);
48 if (ret < 0) {
49 LOG_ERR("Error: entropy_get_entropy failed: %d", ret);
50 }
51 LOG_DBG("n %d, val: %p", len, (void *)ptr_rnd);
52 }
53
LINKLAYER_PLAT_SetupRadioIT(void (* intr_cb)())54 void LINKLAYER_PLAT_SetupRadioIT(void (*intr_cb)())
55 {
56 radio_callback = intr_cb;
57 }
58
LINKLAYER_PLAT_SetupSwLowIT(void (* intr_cb)())59 void LINKLAYER_PLAT_SetupSwLowIT(void (*intr_cb)())
60 {
61 low_isr_callback = intr_cb;
62 }
63
radio_high_prio_isr(void)64 void radio_high_prio_isr(void)
65 {
66 radio_callback();
67
68 HAL_RCCEx_DisableRequestUponRadioWakeUpEvent();
69
70 __ISB();
71
72 ISR_DIRECT_PM();
73 }
74
radio_low_prio_isr(void)75 void radio_low_prio_isr(void)
76 {
77 irq_disable((IRQn_Type)RADIO_SW_LOW_INTR_NUM);
78
79 low_isr_callback();
80
81 /* Check if nested SW radio low interrupt has been requested*/
82 if (radio_sw_low_isr_is_running_high_prio != 0) {
83 NVIC_SetPriority((IRQn_Type) RADIO_SW_LOW_INTR_NUM, RADIO_INTR_PRIO_LOW);
84 radio_sw_low_isr_is_running_high_prio = 0;
85 }
86
87 /* Re-enable SW radio low interrupt */
88 irq_enable((IRQn_Type)RADIO_SW_LOW_INTR_NUM);
89
90 ISR_DIRECT_PM();
91 }
92
93
link_layer_register_isr(void)94 void link_layer_register_isr(void)
95 {
96 ARM_IRQ_DIRECT_DYNAMIC_CONNECT(RADIO_INTR_NUM, 0, 0, reschedule);
97
98 /* Ensure the IRQ is disabled before enabling it at run time */
99 irq_disable((IRQn_Type)RADIO_INTR_NUM);
100
101 irq_connect_dynamic((IRQn_Type)RADIO_INTR_NUM, RADIO_INTR_PRIO_HIGH_Z,
102 (void (*)(const void *))radio_high_prio_isr, NULL, 0);
103
104 irq_enable((IRQn_Type)RADIO_INTR_NUM);
105
106 ARM_IRQ_DIRECT_DYNAMIC_CONNECT(RADIO_SW_LOW_INTR_NUM, 0, 0, reschedule);
107
108 /* Ensure the IRQ is disabled before enabling it at run time */
109 irq_disable((IRQn_Type)RADIO_SW_LOW_INTR_NUM);
110
111 irq_connect_dynamic((IRQn_Type)RADIO_SW_LOW_INTR_NUM, RADIO_SW_LOW_INTR_PRIO,
112 (void (*)(const void *))radio_low_prio_isr, NULL, 0);
113
114 irq_enable((IRQn_Type)RADIO_SW_LOW_INTR_NUM);
115 }
116
117
LINKLAYER_PLAT_TriggerSwLowIT(uint8_t priority)118 void LINKLAYER_PLAT_TriggerSwLowIT(uint8_t priority)
119 {
120 uint8_t low_isr_priority = RADIO_INTR_PRIO_LOW_Z;
121
122 LOG_DBG("Priotity: %d", priority);
123
124 /* Check if a SW low interrupt as already been raised.
125 * Nested call far radio low isr are not supported
126 **/
127
128 if (NVIC_GetActive(RADIO_SW_LOW_INTR_NUM) == 0) {
129 /* No nested SW low ISR, default behavior */
130
131 if (priority == 0) {
132 low_isr_priority = RADIO_SW_LOW_INTR_PRIO;
133 }
134
135 NVIC_SetPriority((IRQn_Type)RADIO_SW_LOW_INTR_NUM, low_isr_priority);
136 } else {
137 /* Nested call detected */
138 /* No change for SW radio low interrupt priority for the moment */
139
140 if (priority != 0) {
141 /* At the end of current SW radio low ISR, this pending SW
142 * low interrupt will run with RADIO_INTR_PRIO_LOW_Z priority
143 **/
144 radio_sw_low_isr_is_running_high_prio = 1;
145 }
146 }
147
148 NVIC_SetPendingIRQ((IRQn_Type)RADIO_SW_LOW_INTR_NUM);
149 }
150
LINKLAYER_PLAT_Assert(uint8_t condition)151 void LINKLAYER_PLAT_Assert(uint8_t condition)
152 {
153 __ASSERT_NO_MSG(condition);
154 }
155
LINKLAYER_PLAT_EnableSpecificIRQ(uint8_t isr_type)156 void LINKLAYER_PLAT_EnableSpecificIRQ(uint8_t isr_type)
157 {
158
159 LOG_DBG("isr_type: %d", isr_type);
160
161 if ((isr_type & LL_HIGH_ISR_ONLY) != 0) {
162 prio_high_isr_counter--;
163 if (prio_high_isr_counter == 0) {
164 irq_enable(RADIO_INTR_NUM);
165 }
166 }
167
168 if ((isr_type & LL_LOW_ISR_ONLY) != 0) {
169 prio_low_isr_counter--;
170 if (prio_low_isr_counter == 0) {
171 irq_enable(RADIO_SW_LOW_INTR_NUM);
172 }
173 }
174
175 if ((isr_type & SYS_LOW_ISR) != 0) {
176 prio_sys_isr_counter--;
177 if (prio_sys_isr_counter == 0) {
178 __set_BASEPRI(local_basepri_value);
179 }
180 }
181 }
182
LINKLAYER_PLAT_DisableSpecificIRQ(uint8_t isr_type)183 void LINKLAYER_PLAT_DisableSpecificIRQ(uint8_t isr_type)
184 {
185
186 LOG_DBG("isr_type: %d", isr_type);
187
188 if ((isr_type & LL_HIGH_ISR_ONLY) != 0) {
189 prio_high_isr_counter++;
190 if (prio_high_isr_counter == 1) {
191 irq_disable(RADIO_INTR_NUM);
192 }
193 }
194
195 if ((isr_type & LL_LOW_ISR_ONLY) != 0) {
196 prio_low_isr_counter++;
197 if (prio_low_isr_counter == 1) {
198 irq_disable(RADIO_SW_LOW_INTR_NUM);
199 }
200 }
201
202 if ((isr_type & SYS_LOW_ISR) != 0) {
203 prio_sys_isr_counter++;
204 if (prio_sys_isr_counter == 1) {
205 local_basepri_value = __get_BASEPRI();
206 __set_BASEPRI_MAX(RADIO_INTR_PRIO_LOW_Z << 4);
207 }
208 }
209 }
210
LINKLAYER_PLAT_StartRadioEvt(void)211 void LINKLAYER_PLAT_StartRadioEvt(void)
212 {
213 __HAL_RCC_RADIO_CLK_SLEEP_ENABLE();
214
215 NVIC_SetPriority(RADIO_INTR_NUM, RADIO_INTR_PRIO_HIGH_Z);
216
217 scm_notifyradiostate(SCM_RADIO_ACTIVE);
218 }
219
LINKLAYER_PLAT_StopRadioEvt(void)220 void LINKLAYER_PLAT_StopRadioEvt(void)
221 {
222 __HAL_RCC_RADIO_CLK_SLEEP_DISABLE();
223
224 NVIC_SetPriority(RADIO_INTR_NUM, RADIO_INTR_PRIO_LOW_Z);
225
226 scm_notifyradiostate(SCM_RADIO_NOT_ACTIVE);
227 }
228
229 /* Link Layer notification for RCO calibration start */
LINKLAYER_PLAT_RCOStartClbr(void)230 void LINKLAYER_PLAT_RCOStartClbr(void)
231 {
232 /* Required only for RCO module usage in the context of LSI2 calibration */
233 }
234
235 /* Link Layer notification for RCO calibration end */
LINKLAYER_PLAT_RCOStopClbr(void)236 void LINKLAYER_PLAT_RCOStopClbr(void)
237 {
238 /* Required only for RCO module usage in the context of LSI2 calibration */
239 }
240
LINKLAYER_PLAT_RequestTemperature(void)241 void LINKLAYER_PLAT_RequestTemperature(void) {}
242
LINKLAYER_PLAT_SCHLDR_TIMING_UPDATE_NOT(Evnt_timing_t * p_evnt_timing)243 void LINKLAYER_PLAT_SCHLDR_TIMING_UPDATE_NOT(Evnt_timing_t *p_evnt_timing) {}
244
LINKLAYER_PLAT_EnableOSContextSwitch(void)245 void LINKLAYER_PLAT_EnableOSContextSwitch(void) {}
246
LINKLAYER_PLAT_DisableOSContextSwitch(void)247 void LINKLAYER_PLAT_DisableOSContextSwitch(void) {}
248