1 /***************************************************************************/ /**
2 * @file rsi_hal_mcu_m4_rom.c
3 *******************************************************************************
4 * # License
5 * <b>Copyright 2024 Silicon Laboratories Inc. www.silabs.com</b>
6 *******************************************************************************
7 *
8 * SPDX-License-Identifier: Zlib
9 *
10 * The licensor of this software is Silicon Laboratories Inc.
11 *
12 * This software is provided 'as-is', without any express or implied
13 * warranty. In no event will the authors be held liable for any damages
14 * arising from the use of this software.
15 *
16 * Permission is granted to anyone to use this software for any purpose,
17 * including commercial applications, and to alter it and redistribute it
18 * freely, subject to the following restrictions:
19 *
20 * 1. The origin of this software must not be misrepresented; you must not
21 * claim that you wrote the original software. If you use this software
22 * in a product, an acknowledgment in the product documentation would be
23 * appreciated but is not required.
24 * 2. Altered source versions must be plainly marked as such, and must not be
25 * misrepresented as being the original software.
26 * 3. This notice may not be removed or altered from any source distribution.
27 *
28 ******************************************************************************/
29
30 #include "sl_si91x_types.h"
31 #include "sl_constants.h"
32 #include "sl_status.h"
33 #include "sl_device.h"
34 #include "sl_rsi_utility.h"
35 #include "rsi_m4.h"
36 #include "rsi_ipmu.h"
37
38 #ifdef SL_WIFI_COMPONENT_INCLUDED
39 #include "sl_si91x_host_interface.h"
40 #endif
41
42 #include "cmsis_os2.h"
43 osEventFlagsId_t ta_events = NULL;
44 #define TA_PKT_TX_DONE (1 << 1)
45 #ifdef SL_SI91X_SIDE_BAND_CRYPTO
46 #define SIDE_BAND_DONE (1 << 2)
47 #endif
48
49 static bool m4_is_using_xtal_without_ta_notification;
50 static bool m4_using_xtal;
51
52 /** @addtogroup SOC4
53 * @{
54 */
55 /**
56 * @fn void sli_si91x_raise_pkt_pending_interrupt_to_ta(void)
57 * @brief Raise the packet pending interrupt to NWP
58 * @param[in] void
59 * @return void
60 */
sli_si91x_raise_pkt_pending_interrupt_to_ta(void)61 void sli_si91x_raise_pkt_pending_interrupt_to_ta(void)
62 {
63 // Write the packet pending interrupt to NWP register
64 M4SS_P2P_INTR_SET_REG = TX_PKT_PENDING_INTERRUPT;
65 osEventFlagsWait(ta_events, TA_PKT_TX_DONE, osFlagsWaitAny, osWaitForever);
66 }
67 /**
68 * @fn bool sli_si91x_is_m4_using_xtal(void);
69 * @brief This API is used to get the whether XTAL is enabled by M4 without notifying NWP
70 * @return true : XTAL is enabled by M4 without notifying NWP
71 * false : XTAL is not enabled by M4
72 */
sli_si91x_is_m4_using_xtal(void)73 bool sli_si91x_is_m4_using_xtal(void)
74 {
75 return m4_is_using_xtal_without_ta_notification;
76 }
77 /**
78 * @fn void sli_si91x_set_m4_is_using_xtal(void);
79 * @brief This API is set XTAL is enabled by M4 without notifying NWP
80 */
sli_si91x_set_m4_is_using_xtal(void)81 void sli_si91x_set_m4_is_using_xtal(void)
82 {
83 m4_is_using_xtal_without_ta_notification = true;
84 }
85
86 /**
87 * @fn bool sli_si91x_is_xtal_in_use_by_m4(void);
88 * @brief This API is used to get the whether XTAL is used by M4 or any of HP peripherals
89 * @return true : XTAL is being used by M4 or HP peripherals
90 * false : XTAL is not being used
91 */
sli_si91x_is_xtal_in_use_by_m4(void)92 bool sli_si91x_is_xtal_in_use_by_m4(void)
93 {
94 return m4_using_xtal;
95 }
96
97 /**
98 * @fn void sli_si91x_set_xtal_in_use_by_m4(void);
99 * @brief This API is used set XTAL is used by M4 or any of HP peripherals
100 */
sli_si91x_set_xtal_in_use_by_m4(void)101 void sli_si91x_set_xtal_in_use_by_m4(void)
102 {
103 m4_using_xtal = true;
104 }
105
106 /**
107 * @fn void sli_si91x_clear_xtal_in_use_by_m4(void);
108 * @brief This API is used to clear XTAL usage by M4 or any of HP peripherals
109 */
sli_si91x_clear_xtal_in_use_by_m4(void)110 void sli_si91x_clear_xtal_in_use_by_m4(void)
111 {
112 m4_using_xtal = false;
113 }
114 /**
115 * @fn void sli_si91x_xtal_turn_off_request_from_m4_to_TA(void);
116 * @brief This API is used to Notify NWP that M4 doesn't requires XTAL clock source
117 */
sli_si91x_xtal_turn_off_request_from_m4_to_TA(void)118 void sli_si91x_xtal_turn_off_request_from_m4_to_TA(void)
119 {
120 if (sli_si91x_is_xtal_in_use_by_m4() == true) {
121 /* If M4 is using XTAL then request NWP to turn OFF XTAL as M4 is going to sleep */
122 sli_si91x_raise_xtal_interrupt_to_ta(TURN_OFF_XTAL_REQUEST);
123 sli_si91x_clear_xtal_in_use_by_m4();
124 }
125 }
126 /**
127 * @fn void sli_si91x_xtal_turn_on_request_from_m4_to_TA(void);
128 * @brief This API is used to Notify NWP that M4 requires XTAL clock source
129 */
sli_si91x_xtal_turn_on_request_from_m4_to_TA(void)130 void sli_si91x_xtal_turn_on_request_from_m4_to_TA(void)
131 {
132 if (sli_si91x_is_xtal_in_use_by_m4() == false) {
133 if (TASS_P2P_INTR_CLEAR_REG & TURN_ON_XTAL_REQUEST) {
134 clear_ta_to_m4_interrupt(TURN_ON_XTAL_REQUEST);
135 } else {
136
137 /* Confirm if the NWP has completed its initialization process */
138 if (sl_si91x_is_device_initialized()) {
139 /* Raise the turn ON xtal interrupt to NWP */
140 sli_si91x_raise_xtal_interrupt_to_ta(TURN_ON_XTAL_REQUEST);
141 /* If M4 is using XTAL then notify NWP to turn ON XTAL during programing common flash*/
142 sli_si91x_raise_xtal_interrupt_to_ta(M4_IS_USING_XTAL_REQUEST);
143 }
144 /*If the 'M4 Enabled XTAL without NWP Notification,
145 * then after net initialization (NWP device initialization), a request to turn on the XTAL will be sent to the NWP*/
146 else {
147 /* set XTAL is enabled by M4 without notifying NWP */
148 sli_si91x_set_m4_is_using_xtal();
149 }
150 }
151 /* Set M4 XTAL usage flag */
152 sli_si91x_set_xtal_in_use_by_m4();
153 }
154 }
155
156 /**
157 * @fn void sli_si91x_raise_xtal_interrupt_to_ta(uint16_t interrupt_no)
158 * @brief Raise the turn on/off xtal interrupt to NWP
159 * @param[in] xtal_enable - true to enable xtal, false to disable xtal
160 * @return void
161 */
sli_si91x_raise_xtal_interrupt_to_ta(uint16_t interrupt_no)162 void sli_si91x_raise_xtal_interrupt_to_ta(uint16_t interrupt_no)
163 {
164 //! Wake up NWP
165 P2P_STATUS_REG |= M4_WAKEUP_TA;
166
167 //!wait for NWP active
168 while (!(P2P_STATUS_REG & TA_IS_ACTIVE))
169 ;
170
171 // Write the turn_on_xtal interrupt to NWP register
172 M4SS_P2P_INTR_SET_REG = interrupt_no;
173
174 //! Poll for bit to clear
175 //!Wait for NWP using flash bit
176 while (!(TASS_P2P_INTR_CLEAR_REG & interrupt_no))
177 ;
178 clear_ta_to_m4_interrupt(interrupt_no);
179
180 sl_si91x_host_clear_sleep_indicator();
181 }
182
183 /**
184 * @fn void sli_si91x_send_m4_xtal_usage_notification_to_ta(void);
185 * @brief This API sends a notification to the NWP indicating whether
186 * the M4 core is currently utilizing the XTAL as its clock source.
187 */
sli_si91x_send_m4_xtal_usage_notification_to_ta(void)188 void sli_si91x_send_m4_xtal_usage_notification_to_ta(void)
189 {
190
191 #if !(SLI_SI91X_MCU_PSRAM_PRESENT)
192 /* Check whether M4 is using XTAL */
193 if (sli_si91x_is_m4_using_xtal() == true)
194 #endif
195 {
196 /* If M4 is using XTAL then request NWP to turn ON XTAL*/
197 sli_si91x_raise_xtal_interrupt_to_ta(TURN_ON_XTAL_REQUEST);
198 /* If M4 is using XTAL then notify NWP to turn ON XTAL during programing common flash*/
199 sli_si91x_raise_xtal_interrupt_to_ta(M4_IS_USING_XTAL_REQUEST);
200 }
201 }
202
203 #ifdef SL_SI91X_SIDE_BAND_CRYPTO
204 /**
205 * @fn void sli_si91x_raise_side_band_interrupt_to_ta(void)
206 * @brief Raise the side band interrupt to NWP
207 * @param[in] void
208 * @return void
209 */
sli_si91x_raise_side_band_interrupt_to_ta(void)210 void sli_si91x_raise_side_band_interrupt_to_ta(void)
211 {
212 // Write the packet pending interrupt to NWP register
213 M4SS_P2P_INTR_SET_REG = SIDE_BAND_CRYPTO_INTR;
214 }
215 #endif
216
217 /**
218 * @fn void raise_m4_to_ta_interrupt(uint32_t interrupt_no)
219 * @brief Set interrupt.
220 * @param[in] interrupt_no - Process of a interrupt number
221 * @return void
222 */
223
raise_m4_to_ta_interrupt(uint32_t interrupt_no)224 void raise_m4_to_ta_interrupt(uint32_t interrupt_no)
225 {
226 M4SS_P2P_INTR_SET_REG = interrupt_no;
227 }
228
229 /**
230 * @fn void mask_ta_interrupt(uint32_t interrupt_no)
231 * @brief Process a interrupt mask.
232 * @param[in] void
233 * @return void
234 */
mask_ta_interrupt(uint32_t interrupt_no)235 void mask_ta_interrupt(uint32_t interrupt_no)
236 {
237 TASS_P2P_INTR_MASK_SET = interrupt_no;
238 }
239
240 /**
241 * @fn void clear_ta_to_m4_interrupt(uint32_t interrupt_no)
242 * @brief Clear interrupt raised by NWP.
243 * @param[in] interrupt_no - Process of a interrupt number
244 * @return void
245 */
clear_ta_to_m4_interrupt(uint32_t interrupt_no)246 void clear_ta_to_m4_interrupt(uint32_t interrupt_no)
247 {
248 TASS_P2P_INTR_CLEAR = interrupt_no;
249 TASS_P2P_INTR_CLR_REG = interrupt_no;
250 }
251
252 /**
253 * @fn void sli_m4_interrupt_isr(void)
254 * @brief Raise the packet pending interrupt to NWP
255 * @param[in] void
256 * @return void
257 */
258
sli_m4_interrupt_isr(void)259 sl_status_t sli_m4_interrupt_isr(void)
260 {
261 if (TASS_P2P_INTR_CLEAR & TX_PKT_TRANSFER_DONE_INTERRUPT) {
262
263 osEventFlagsSet(ta_events, TA_PKT_TX_DONE);
264 // Clear the interrupt
265 clear_ta_to_m4_interrupt(TX_PKT_TRANSFER_DONE_INTERRUPT);
266
267 } else if (TASS_P2P_INTR_CLEAR & RX_PKT_TRANSFER_DONE_INTERRUPT) {
268
269 // Call done interrupt isr
270 sl_status_t status = sli_receive_from_ta_done_isr();
271 VERIFY_STATUS_AND_RETURN(status);
272
273 // Clear the interrupt
274 clear_ta_to_m4_interrupt(RX_PKT_TRANSFER_DONE_INTERRUPT);
275
276 } else if (TASS_P2P_INTR_CLEAR & TA_RSI_BUFFER_FULL_CLEAR_EVENT) {
277
278 mask_ta_interrupt(TA_RSI_BUFFER_FULL_CLEAR_EVENT);
279
280 sli_si91x_set_event(SL_SI91X_TA_BUFFER_FULL_CLEAR_EVENT);
281
282 // Clear the interrupt
283 clear_ta_to_m4_interrupt(TA_RSI_BUFFER_FULL_CLEAR_EVENT);
284 }
285 #if defined(SLI_SI917) || defined(SLI_SI915)
286 else if (TASS_P2P_INTR_CLEAR & TA_WRITING_ON_COMM_FLASH) {
287 //! moves m4 app to RAM and polls for NWP done
288 sl_mv_m4_app_from_flash_to_ram(TA_WRITES_ON_COMM_FLASH);
289 // Clear the interrupt
290 clear_ta_to_m4_interrupt(TA_WRITING_ON_COMM_FLASH);
291 } else if (TASS_P2P_INTR_CLEAR & NWP_DEINIT_IN_COMM_FLASH) {
292 //! moves m4 app to RAM and polls for NWP done
293 sl_mv_m4_app_from_flash_to_ram(M4_WAIT_FOR_NWP_DEINIT);
294 // Clear the interrupt
295 clear_ta_to_m4_interrupt(NWP_DEINIT_IN_COMM_FLASH);
296 }
297 //! Below changes are requried for M4 Image upgration in dual flash config
298 else if (TASS_P2P_INTR_CLEAR & M4_IMAGE_UPGRADATION_PENDING_INTERRUPT) {
299 //! moves m4 app to RAM and polls for NWP done
300 sl_mv_m4_app_from_flash_to_ram(UPGRADE_M4_IMAGE_OTA);
301 // Clear the interrupt
302 clear_ta_to_m4_interrupt(M4_IMAGE_UPGRADATION_PENDING_INTERRUPT);
303 }
304 #endif
305 #ifdef SL_SI91X_SIDE_BAND_CRYPTO
306 //! Below changes are requried for SIDE BAND CRYPTO
307 else if (TASS_P2P_INTR_CLEAR & SIDE_BAND_CRYPTO_DONE) {
308 osEventFlagsSet(ta_events, SIDE_BAND_DONE);
309 // Clear the interrupt
310 clear_ta_to_m4_interrupt(SIDE_BAND_CRYPTO_DONE);
311 }
312 #endif
313 else {
314 SL_DEBUG_LOG("\r\n INVALID INTERRUPT \r\n", 0);
315 BREAKPOINT();
316 }
317 return SL_STATUS_OK;
318 }
319
320 /**
321 * @fn sl_status_t sli_receive_from_ta_done_isr(void)
322 * @brief Called when DMA done for RX packet is received
323 * @param[in] global_cb_p - pointer to the global control block
324 * @return void
325 */
sli_receive_from_ta_done_isr(void)326 sl_status_t sli_receive_from_ta_done_isr(void)
327 {
328 #ifdef SL_WIFI_COMPONENT_INCLUDED
329 extern sl_wifi_buffer_t *rx_pkt_buffer;
330 extern sl_si91x_buffer_queue_t sli_ahb_bus_rx_queue;
331 // Add to rx packet to CCP queue
332 sl_status_t status = sli_si91x_add_to_queue(&sli_ahb_bus_rx_queue, rx_pkt_buffer);
333 VERIFY_STATUS_AND_RETURN(status);
334
335 //! Set event RX pending event to host
336 sl_si91x_host_set_bus_event(SL_SI91X_NCP_HOST_BUS_RX_EVENT);
337 #endif
338
339 return SL_STATUS_OK;
340 }
341
342 /*==================================================*/
343 /**
344 * @fn sl_status_t sl_si91x_bus_read_interrupt_status(uint8_t *int_status)
345 * @brief Returns the value of the Interrupt register
346 * @param[in] status
347 * @param[out] buffer full status reg value
348 * @return errorcode
349 * 0 = Success
350 * -2 = Reg read failure
351 */
sl_si91x_bus_read_interrupt_status(uint16_t * int_status)352 sl_status_t sl_si91x_bus_read_interrupt_status(uint16_t *int_status)
353 {
354 *int_status = (uint8_t)HOST_INTR_STATUS_REG;
355
356 return RSI_SUCCESS;
357 }
358
si91x_req_wakeup(void)359 sl_status_t si91x_req_wakeup(void)
360 {
361 P2P_STATUS_REG |= M4_wakeup_TA;
362 if (!(P2P_STATUS_REG & TA_is_active)) {
363 //!TBD Need add timeout
364 while (!(P2P_STATUS_REG & TA_is_active))
365 ;
366 }
367 return SL_STATUS_OK;
368 }
369
sl_si91x_host_clear_sleep_indicator(void)370 void sl_si91x_host_clear_sleep_indicator(void)
371 {
372 P2P_STATUS_REG &= ~M4_wakeup_TA;
373 }
374
IRQ074_Handler(void)375 void IRQ074_Handler(void)
376 {
377 sli_m4_interrupt_isr();
378 }
379
sl_si91x_ta_events_init(void)380 void sl_si91x_ta_events_init(void)
381 {
382 if (ta_events == NULL) {
383 ta_events = osEventFlagsNew(NULL);
384 }
385 }
386 /** @} */