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