1 /***************************************************************************/ /**
2  * @file  sli_siwx917_soc.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 #if defined(SL_COMPONENT_CATALOG_PRESENT)
31 #include "sl_component_catalog.h"
32 #endif
33 #include "system_si91x.h"
34 #include "rsi_error.h"
35 #include "rsi_ccp_common.h"
36 #include "sl_si91x_constants.h"
37 #include "rsi_ipmu.h"
38 #include "rsi_rom_clks.h"
39 #include "rsi_rom_ulpss_clk.h"
40 #include "rsi_m4.h"
41 #include "sl_si91x_status.h"
42 #include "sli_siwx917_timer.h"
43 #include "sli_siwx917_soc.h"
44 #include "sl_constants.h"
45 #include "rsi_temp_sensor.h"
46 #include "sl_si91x_host_interface.h"
47 #if defined(SL_CATALOG_KERNEL_PRESENT)
48 #include "cmsis_os2.h"
49 #endif
50 
51 #define RSI_HAL_MAX_WR_BUFF_LEN 4096
52 
53 #define SI91X_INTERFACE_OUT_REGISTER       (*(uint32_t *)(RSI_HOST_INTF_REG_OUT))
54 #define SI91X_INTERFACE_IN_REGISTER        (*(uint32_t *)(RSI_HOST_INTF_REG_IN))
55 #define SI91X_INTERFACE_STATUS_REGISTER    (*(uint32_t *)(RSI_HOST_INTF_STATUS_REG))
56 #define SI91X_PING_BUFFER_ADDRESS_REGISTER (*(uint32_t *)(RSI_PING_BUFFER_ADDR))
57 #define SI91X_PONG_BUFFER_ADDRESS_REGISTER (*(uint32_t *)(RSI_PONG_BUFFER_ADDR))
58 
59 typedef struct {
60   uint8_t _[2048];
61 } sli_si91x_pingpong_buffer_t;
62 
63 #define SI91X_PING_BUFFER ((sli_si91x_pingpong_buffer_t *)(0x19000))
64 #define SI91X_PONG_BUFFER ((sli_si91x_pingpong_buffer_t *)(0x1A000))
65 
66 /**
67  * @fn          int16_t rsi_bl_select_option(uint8_t cmd)
68  * @brief       Send firmware load request to module or update default configurations.
69  * @param[in]   cmd - type of configuration to be saved \n
70  *                    BURN_NWP_FW                    - 0x42 \n
71  *                    LOAD_NWP_FW                    - 0x31 \n
72  *                    LOAD_DEFAULT_NWP_FW_ACTIVE_LOW - 0x71 \n
73  * @return      0              - Success \n
74  *              Non-Zero Value - Failure \n
75  *                               -28 - Firmware Load or Upgrade timeout error \n
76  *                               -14 - Valid Firmware not present \n
77  *                               -15 - Invalid Option
78  *
79  */
80 /// @private
rsi_bl_select_option(uint8_t cmd)81 int16_t rsi_bl_select_option(uint8_t cmd)
82 {
83   uint16_t boot_cmd   = 0;
84   int16_t retval      = 0;
85   uint16_t read_value = 0;
86   sl_si91x_timer_t timer_instance;
87 
88   SI91X_INTERFACE_OUT_REGISTER = boot_cmd;
89 
90   if (cmd == BURN_NWP_FW) {
91     boot_cmd = RSI_HOST_INTERACT_REG_VALID_FW | cmd;
92   } else {
93     boot_cmd = RSI_HOST_INTERACT_REG_VALID | cmd;
94   }
95   retval = sli_si91x_send_boot_instruction(RSI_REG_WRITE, &boot_cmd);
96   if (retval < 0) {
97     return retval;
98   }
99 
100   sl_si91x_timer_init(&timer_instance, 300);
101 
102   while ((cmd != LOAD_NWP_FW) && (cmd != LOAD_DEFAULT_NWP_FW_ACTIVE_LOW)) {
103     retval = sli_si91x_send_boot_instruction(RSI_REG_READ, &read_value);
104     if (retval < 0) {
105       return retval;
106     }
107     if (cmd == BURN_NWP_FW) {
108       if (read_value == (RSI_HOST_INTERACT_REG_VALID | RSI_SEND_RPS_FILE)) {
109         break;
110       }
111     }
112 
113     else if (read_value == (RSI_HOST_INTERACT_REG_VALID | cmd)) {
114       break;
115     }
116     if (sl_si91x_timer_expired(&timer_instance)) {
117       return RSI_ERROR_FW_LOAD_OR_UPGRADE_TIMEOUT;
118     }
119   }
120   if ((cmd == LOAD_NWP_FW) || (cmd == LOAD_DEFAULT_NWP_FW_ACTIVE_LOW)) {
121     sl_si91x_timer_init(&timer_instance, 3000);
122     do {
123       retval = sli_si91x_send_boot_instruction(RSI_REG_READ, &read_value);
124       if (retval < 0) {
125         return retval;
126       }
127       if ((read_value & 0xF000) == (RSI_HOST_INTERACT_REG_VALID_FW & 0xF000)) {
128         if ((read_value & 0xFF) == VALID_FIRMWARE_NOT_PRESENT) {
129 #ifdef RSI_DEBUG_PRINT
130           RSI_DPRINT(RSI_PL4, "VALID_FIRMWARE_NOT_PRESENT\n");
131 #endif
132           return RSI_ERROR_VALID_FIRMWARE_NOT_PRESENT;
133         }
134         if ((read_value & 0xFF) == RSI_INVALID_OPTION) {
135 #ifdef RSI_DEBUG_PRINT
136           RSI_DPRINT(RSI_PL4, "INVALID CMD\n");
137 #endif
138 
139           return RSI_ERROR_INVALID_OPTION;
140         }
141         if ((read_value & 0xFF) == RSI_CHECKSUM_SUCCESS) {
142 #ifdef RSI_DEBUG_PRINT
143           RSI_DPRINT(RSI_PL4, "LOAD SUCCESS\n");
144 #endif
145           break;
146         }
147       }
148       if (sl_si91x_timer_expired(&timer_instance)) {
149         return RSI_ERROR_FW_LOAD_OR_UPGRADE_TIMEOUT;
150       }
151 
152     } while (1);
153   }
154   return retval;
155 }
156 
157 /**
158  * @fn          int16_t sli_si91x_send_boot_instruction(uint8_t type, uint16_t *data)
159  * @brief       Send boot instructions to module.
160  * @param[in]   type - type of the insruction to perform \n
161  *                     0xD1 - RSI_REG_READ \n
162  *                     0xD2 - RSI_REG_WRITE \n
163  *                     0xD5 - RSI_PING_WRITE \n
164  *                     0xD4 - RSI_PONG_WRITE \n
165  *                     0x42 - BURN_NWP_FW \n
166  *                     0x31 - LOAD_NWP_FW \n
167  *                     0x71 - LOAD_DEFAULT_NWP_FW_ACTIVE_LOW
168  * @param[in]   data - pointer to data which is to be read/write \n
169  * @return      0              - Success \n
170  *              Non-Zero Value - Failure \n
171  *                               -28       - Firmware Load or Upgrade timeout error \n
172  *                                -2       - Invalid Parameter \n
173  *                                -1 or -2 - SPI Failure
174  * @note        This is a proprietry API and it is not recommended to be used by the user directly.
175  */
176 /// @private
sli_si91x_send_boot_instruction(uint8_t type,uint16_t * data)177 int16_t sli_si91x_send_boot_instruction(uint8_t type, uint16_t *data)
178 {
179   int16_t retval     = 0;
180   uint32_t cmd       = 0;
181   uint16_t read_data = 0;
182   sl_si91x_timer_t timer_instance;
183 
184   switch (type) {
185     case RSI_REG_READ:
186       *data = (uint16_t)SI91X_INTERFACE_OUT_REGISTER;
187       break;
188 
189     case RSI_REG_WRITE:
190       SI91X_INTERFACE_IN_REGISTER = *data;
191       break;
192 
193     case BURN_NWP_FW:
194       cmd = BURN_NWP_FW | RSI_HOST_INTERACT_REG_VALID;
195 
196       SI91X_INTERFACE_IN_REGISTER = cmd;
197 
198       sl_si91x_timer_init(&timer_instance, 300);
199 
200       do {
201         read_data = (uint16_t)SI91X_INTERFACE_OUT_REGISTER;
202         if (sl_si91x_timer_expired(&timer_instance)) {
203           return RSI_ERROR_FW_LOAD_OR_UPGRADE_TIMEOUT;
204         }
205       } while (read_data != (RSI_SEND_RPS_FILE | RSI_HOST_INTERACT_REG_VALID));
206       break;
207 
208     case LOAD_NWP_FW:
209       SI91X_INTERFACE_IN_REGISTER = LOAD_NWP_FW | RSI_HOST_INTERACT_REG_VALID;
210       break;
211 
212     case LOAD_DEFAULT_NWP_FW_ACTIVE_LOW:
213       SI91X_INTERFACE_IN_REGISTER = LOAD_DEFAULT_NWP_FW_ACTIVE_LOW | RSI_HOST_INTERACT_REG_VALID;
214       break;
215 
216     default:
217       retval = RSI_ERROR_INVALID_PARAM;
218       break;
219   }
220   return retval;
221 }
222 
223 /**
224  * @fn          int16 rsi_waitfor_boardready(void)
225  * @brief       Waits to receive board ready from WiFi module
226  * @param[in]   none
227  * @param[out]  none
228  * @return      errCode
229  *              0   = SUCCESS
230  *              < 0 = Failure
231  *              -7  = Error in OS operation
232  *              -9  = Bootup options last configuration not saved
233  *              -10 = Bootup options checksum failed
234  *              -11 = Bootloader version mismatch
235  *              -12 = Board ready not received
236  * @section description
237  * This API is used to check board ready from WiFi module.
238  */
rsi_waitfor_boardready(void)239 int16_t rsi_waitfor_boardready(void)
240 {
241   int16_t retval      = 0;
242   uint16_t read_value = 0;
243 
244   retval = rsi_boot_insn(REG_READ, &read_value);
245 
246   if (retval < 0) {
247     return retval;
248   }
249   if (read_value == 0) {
250     return RSI_ERROR_IN_OS_OPERATION;
251   }
252   if ((read_value & 0xFF00) == (HOST_INTERACT_REG_VALID_READ & 0xFF00)) {
253     if ((read_value & 0xFF) == RSI_BOOTUP_OPTIONS_LAST_CONFIG_NOT_SAVED) {
254 #ifdef RSI_DEBUG_PRINT
255       RSI_DPRINT(RSI_PL3, "BOOTUP OPTIOINS LAST CONFIGURATION NOT SAVED\n");
256 #endif
257       return RSI_ERROR_BOOTUP_OPTIONS_NOT_SAVED;
258     } else if ((read_value & 0xFF) == RSI_BOOTUP_OPTIONS_CHECKSUM_FAIL) {
259 #ifdef RSI_DEBUG_PRINT
260       RSI_DPRINT(RSI_PL3, "BOOTUP OPTIONS CHECKSUM FAIL\n");
261 #endif
262       return RSI_ERROR_BOOTUP_OPTIONS_CHECKSUM_FAIL;
263     }
264 #if defined(BOOTLOADER_VERSION_CHECK) && (BOOTLOADER_VERSION_CHECK == 1)
265     else if ((read_value & 0xFF) == BOOTLOADER_VERSION) {
266 #ifdef RSI_DEBUG_PRINT
267       RSI_DPRINT(RSI_PL3, "BOOTLOADER VERSION CORRECT\n");
268 #endif
269     } else {
270 #ifdef RSI_DEBUG_PRINT
271       RSI_DPRINT(RSI_PL3, "BOOTLOADER VERSION NOT MATCHING\n");
272 #endif
273 
274       return RSI_ERROR_BOOTLOADER_VERSION_NOT_MATCHING;
275     }
276 #endif
277 
278 #ifdef RSI_DEBUG_PRINT
279     RSI_DPRINT(RSI_PL3, "RECIEVED BOARD READY\n");
280 #endif
281     return RSI_ERROR_NONE;
282   }
283 
284 #ifdef RSI_DEBUG_PRINT
285   RSI_DPRINT(RSI_PL3, "WAITING FOR BOARD READY\n");
286 #endif
287   return RSI_ERROR_WAITING_FOR_BOARD_READY;
288 }
289 
290 /**
291  * @fn          int16 rsi_select_option(uint8 cmd)
292  * @brief       Sends cmd to select option to load or update configuration
293  * @param[in]   uint8 cmd, type of configuration to be saved
294  * @param[out]  none
295  * @return      errCode
296                 < 0 = Command issue failed
297  *              0  = SUCCESS
298  * @section description
299  * This API is used to send firmware load request to WiFi module or update default configurations.
300  */
rsi_select_option(uint8_t cmd)301 int16_t rsi_select_option(uint8_t cmd)
302 {
303   uint16_t boot_cmd             = 0;
304   int16_t retval                = 0;
305   uint16_t read_value           = 0;
306   uint8_t image_number          = 0;
307   volatile int32_t loop_counter = 0;
308 
309   boot_cmd = HOST_INTERACT_REG_VALID | cmd;
310   if (cmd == CHECK_NWP_INTEGRITY) {
311     boot_cmd &= 0xF0FF;
312     boot_cmd = boot_cmd | (uint16_t)(image_number << 8);
313   }
314   retval = rsi_boot_insn(REG_WRITE, &boot_cmd);
315   if (retval < 0) {
316     return retval;
317   }
318 
319   if ((cmd != LOAD_NWP_FW) && (cmd != LOAD_DEFAULT_NWP_FW_ACTIVE_LOW) && (cmd != RSI_JUMP_TO_PC)) {
320     RSI_RESET_LOOP_COUNTER(loop_counter);
321     RSI_WHILE_LOOP((uint32_t)loop_counter, RSI_LOOP_COUNT_SELECT_OPTION)
322     {
323       retval = rsi_boot_insn(REG_READ, &read_value);
324       if (retval < 0) {
325         return retval;
326       }
327       if (cmd == CHECK_NWP_INTEGRITY) {
328         if ((read_value & 0xFF) == RSI_CHECKSUM_SUCCESS) {
329 #ifdef RSI_DEBUG_PRINT
330           RSI_DPRINT(RSI_PL3, "CHECKSUM SUCCESS\n");
331 #endif
332         } else if (read_value == RSI_CHECKSUM_FAILURE) {
333 #ifdef RSI_DEBUG_PRINT
334           RSI_DPRINT(RSI_PL3, "CHECKSUM FAIL\n");
335 #endif
336         } else if (read_value == RSI_CHECKSUM_INVALID_ADDRESS) {
337 #ifdef RSI_DEBUG_PRINT
338           RSI_DPRINT(RSI_PL3, "Invalid Address \n");
339 #endif
340         }
341       }
342       if (read_value == (HOST_INTERACT_REG_VALID | cmd)) {
343         break;
344       }
345     }
346     RSI_CHECK_LOOP_COUNTER(loop_counter, RSI_LOOP_COUNT_SELECT_OPTION);
347   } else if ((cmd == LOAD_NWP_FW) || (cmd == LOAD_DEFAULT_NWP_FW_ACTIVE_LOW) || (cmd == RSI_JUMP_TO_PC)) {
348     retval = rsi_boot_insn(REG_READ, &read_value);
349     if (retval < 0) {
350       return retval;
351     }
352     if ((read_value & 0xFF) == VALID_FIRMWARE_NOT_PRESENT) {
353 #ifdef RSI_DEBUG_PRINT
354       RSI_DPRINT(RSI_PL3, "VALID_FIRMWARE_NOT_PRESENT\n");
355 #endif
356       return RSI_ERROR_VALID_FIRMWARE_NOT_PRESENT;
357     }
358     if ((read_value & 0xFF) == RSI_INVALID_OPTION) {
359 #ifdef RSI_DEBUG_PRINT
360       RSI_DPRINT(RSI_PL3, "INVALID CMD\n");
361 #endif
362       return RSI_ERROR_COMMAND_NOT_SUPPORTED;
363     }
364   }
365   return retval;
366 }
367 
368 /**
369  * @fn          int16 rsi_boot_insn(uint8 type, uint16 *data)
370  * @brief       Sends boot instructions to WiFi module
371  * @param[in]   uint8 type, type of the insruction to perform
372  * @param[in]   uint32 *data, pointer to data which is to be read/write
373  * @param[out]  none
374  * @return      errCode
375  *              < 0  = Command issued failure/Invalid command
376  *                0  = SUCCESS
377  *              > 0  = Read value
378  * @section description
379  * This API is used to send boot instructions to WiFi module.
380  */
381 
rsi_boot_insn(uint8_t type,uint16_t * data)382 int16_t rsi_boot_insn(uint8_t type, uint16_t *data)
383 {
384   int16_t retval                = 0;
385   uint16_t read_data            = 0;
386   volatile int32_t loop_counter = 0;
387 #ifdef RSI_DEBUG_PRINT
388   RSI_DPRINT(RSI_PL3, "\nBootInsn\n");
389 #endif
390 
391   switch (type) {
392     case REG_READ:
393       *data = (uint16_t)SI91X_INTERFACE_OUT_REGISTER;
394       break;
395 
396     case REG_WRITE:
397       SI91X_INTERFACE_IN_REGISTER = *data;
398       break;
399 
400     case PING_WRITE:
401       memcpy(SI91X_PING_BUFFER, data, sizeof(sli_si91x_pingpong_buffer_t));
402       SI91X_INTERFACE_IN_REGISTER = 0xab49;
403       break;
404 
405     case PONG_WRITE:
406       memcpy(SI91X_PONG_BUFFER, data, sizeof(sli_si91x_pingpong_buffer_t));
407       SI91X_INTERFACE_IN_REGISTER = 0xab4f;
408       break;
409 
410     case BURN_NWP_FW:
411       SI91X_INTERFACE_IN_REGISTER = BURN_NWP_FW | HOST_INTERACT_REG_VALID;
412 
413       RSI_RESET_LOOP_COUNTER(loop_counter);
414       RSI_WHILE_LOOP((uint32_t)loop_counter, RSI_LOOP_COUNT_UPGRADE_IMAGE)
415       {
416         read_data = (uint16_t)SI91X_INTERFACE_OUT_REGISTER;
417         if (read_data == (RSI_SEND_RPS_FILE | HOST_INTERACT_REG_VALID)) {
418           break;
419         }
420       }
421       RSI_CHECK_LOOP_COUNTER(loop_counter, RSI_LOOP_COUNT_UPGRADE_IMAGE);
422       break;
423 
424     case LOAD_NWP_FW:
425       SI91X_INTERFACE_IN_REGISTER = LOAD_NWP_FW | HOST_INTERACT_REG_VALID;
426       break;
427     case LOAD_DEFAULT_NWP_FW_ACTIVE_LOW:
428       SI91X_INTERFACE_IN_REGISTER = LOAD_DEFAULT_NWP_FW_ACTIVE_LOW | HOST_INTERACT_REG_VALID;
429       break;
430     case RSI_UPGRADE_BL:
431       SI91X_INTERFACE_IN_REGISTER = RSI_UPGRADE_BL | HOST_INTERACT_REG_VALID;
432       RSI_RESET_LOOP_COUNTER(loop_counter);
433       RSI_WHILE_LOOP((uint32_t)loop_counter, RSI_LOOP_COUNT_UPGRADE_IMAGE)
434       {
435         read_data = (uint16_t)SI91X_INTERFACE_OUT_REGISTER;
436         if (read_data == (RSI_SEND_RPS_FILE | HOST_INTERACT_REG_VALID)) {
437           break;
438         }
439       }
440       RSI_CHECK_LOOP_COUNTER(loop_counter, RSI_LOOP_COUNT_UPGRADE_IMAGE);
441       break;
442     default:
443       retval = -2;
444       break;
445   }
446   return retval;
447 }
448 
unmask_ta_interrupt(uint32_t interrupt_no)449 void unmask_ta_interrupt(uint32_t interrupt_no)
450 {
451   TASS_P2P_INTR_MASK_CLR = interrupt_no;
452 }
453 
sli_m4_ta_interrupt_init(void)454 void sli_m4_ta_interrupt_init(void)
455 {
456 #if defined(SLI_SI917) || defined(SLI_SI915)
457   //! Unmask the interrupt
458   unmask_ta_interrupt(TX_PKT_TRANSFER_DONE_INTERRUPT | RX_PKT_TRANSFER_DONE_INTERRUPT | TA_WRITING_ON_COMM_FLASH
459                       | NWP_DEINIT_IN_COMM_FLASH
460 #ifdef SLI_SI91X_MCU_FW_UPGRADE_OTA_DUAL_FLASH
461                       | M4_IMAGE_UPGRADATION_PENDING_INTERRUPT
462 #endif
463 #ifdef SL_SI91X_SIDE_BAND_CRYPTO
464                       | SIDE_BAND_CRYPTO_DONE
465 #endif
466   );
467 #else
468   //! Unmask the interrupt
469   unmask_ta_interrupt(TX_PKT_TRANSFER_DONE_INTERRUPT | RX_PKT_TRANSFER_DONE_INTERRUPT);
470 #endif
471   P2P_STATUS_REG |= M4_is_active;
472 
473   *(volatile uint32_t *)0xE000E108 = 0x00000400;
474 
475   //! Set P2P Intr priority
476   NVIC_SetPriority(TASS_P2P_IRQn, TASS_P2P_INTR_PRI);
477 
478   return;
479 }
480 
sl_si91x_ulp_wakeup_init(void)481 void sl_si91x_ulp_wakeup_init(void)
482 {
483   // for compilation
484 }
485