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 /** @} */