1 /******************************************************************************
2 * @file  system_si91x.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 /**
31  * Includes
32  */
33 
34 #include <stdint.h>
35 #include "system_si91x.h"
36 #include "rsi_error.h"
37 #include "rsi_ccp_common.h"
38 #include "rsi_ps_ram_func.h"
39 #include "rsi_ipmu.h"
40 #include "rsi_pll.h"
41 #include "rsi_power_save.h"
42 #include "rsi_ulpss_clk.h"
43 #include "rsi_rom_ulpss_clk.h"
44 #include "rsi_rom_clks.h"
45 #if defined(SLI_SI91X_MCU_PSRAM_PRESENT)
46 #include "rsi_d_cache.h"
47 #endif
48 
49 #if defined(SI91X_32kHz_EXTERNAL_OSCILLATOR)
50 #include "sl_si91x_external_oscillator.h"
51 #define MCU_RETENTION_BASE_ADDRESS 0x24048600
52 #define NPSS_GPIO_CTRL             (MCU_RETENTION_BASE_ADDRESS + 0x1C)
53 #endif
54 
55 #if defined(SLI_SI915)
56 #define BG_LDO_REG1        0x129 //IPMU Bandgap Top register
57 #define LDO_0P6_BYPASS_BIT 21    //Retention LDO bypass
58 #endif
59 /*----------------------------------------------------------------------------
60   Define clocks
61  *----------------------------------------------------------------------------*/
62 /*Cortex-m4 FPU registers*/
63 #define FPU_CPACR       0xE000ED88
64 #define SCB_MVFR0       0xE000EF40
65 #define SCB_MVFR0_RESET 0x10110021
66 #define SCB_MVFR1       0xE000EF44
67 #define SCB_MVFR1_RESET 0x11000011
68 
69 /*Simulation macros*/
70 #define SIMULATION_SILICON_REV  0x14
71 #define SIMULATION_PACKAGE_TYPE 0x1
72 
73 /* Constants required to manipulate the NVIC. */
74 /*----------------------------------------------------------------------------
75   Clock Variable definitions
76  *----------------------------------------------------------------------------*/
77 uint32_t SystemCoreClock; /*!< System Clock Frequency (Core Clock)*/
78 
79 SYSTEM_CLOCK_SOURCE_FREQUENCIES_T system_clocks; /*!< System Clock sources Frequencies */
80 
81 uint32_t npssIntrState = 0;
82 uint32_t __sp;
83 uint32_t SiliconRev;
84 uint32_t package_type;
85 
86 /**
87  * @fn     void SystemCoreClockUpdate (void)
88  * @brief  Updates the SystemCoreClock with current core Clock
89  *         retrieved from cpu registers.
90  * @return none
91  */
SystemCoreClockUpdate(void)92 void SystemCoreClockUpdate(void) /* Get Core Clock Frequency      */
93 {
94   const retention_boot_status_word_t *retention_reg = (const retention_boot_status_word_t *)MCURET_BOOTSTATUS;
95 
96   /*Updated the default SOC clock frequency*/
97   SystemCoreClock = DEFAULT_40MHZ_CLOCK;
98 #if (defined(RAM_COMPILATION) && defined(SLI_SI91X_MCU_COMMON_FLASH_MODE))
99   /*Initialize QSPI for RAM based execution for common flash boards  */
100   RSI_FLASH_Initialize();
101 #endif
102 #ifndef SIMULATION
103 #ifdef RAM_COMPILATION
104   if (retention_reg->product_mode == MCU) {
105     SiliconRev   = SIMULATION_SILICON_REV;
106     package_type = SIMULATION_PACKAGE_TYPE;
107   } else {
108     SiliconRev   = SILICON_REV_WMCU;
109     package_type = PACKAGE_TYPE_WMCU;
110   }
111 #else
112   if (retention_reg->product_mode == MCU) {
113     SiliconRev   = SILICON_REV_MCU;
114     package_type = PACKAGE_TYPE_MCU;
115   } else {
116     SiliconRev   = SILICON_REV_WMCU;
117     package_type = PACKAGE_TYPE_WMCU;
118   }
119 #endif
120 #if defined(SLI_SI91X_MCU_PSRAM_PRESENT)
121   rsi_d_cache_invalidate_all();
122 #endif
123   /*Initialize IPMU and MCU FSM blocks */
124   RSI_Ipmu_Init();
125   /*configures chip supply mode */
126   RSI_Configure_Ipmu_Mode();
127 
128 #endif
129   /*Default clock mux configurations */
130   RSI_CLK_PeripheralClkEnable3(M4CLK, M4_SOC_CLK_FOR_OTHER_ENABLE);
131 
132   /* NWP clock is selected as 40MHZ clock from MCU */
133   MCU_FSM->MCU_FSM_REF_CLK_REG_b.TASS_REF_CLK_SEL = ULP_MHZ_RC_CLK;
134   /* Changing NPSS GPIO 0 mode to 0, to disable buck-boost enable mode*/
135   MCU_RET->NPSS_GPIO_CNTRL[0].NPSS_GPIO_CTRLS_b.NPSS_GPIO_MODE = 0;
136   /* Configuring MCU FSM clock for BG_PMU */
137   RSI_IPMU_ClockMuxSel(2);
138 
139 #if defined(SI91X_32kHz_EXTERNAL_OSCILLATOR)
140 
141   // Configuring the UULP_GPIOs for external oscillator
142   *(volatile uint32 *)(NPSS_GPIO_CTRL + (4 * OSC_UULP_GPIO)) = (BIT(3) | UULP_GPIO_OSC_MODE);
143   MCUAON_GEN_CTRLS_REG |= BIT(0);
144   MCUAON_GEN_CTRLS_REG;
145 
146   // Configuring RC 32KHz Clock for LF-FSM
147   RSI_PS_FsmLfClkSel(KHZ_RC_CLK_SEL);
148 #else
149   /* Configuring XTAL 32.768kHz Clock for LF-FSM */
150   RSI_PS_FsmLfClkSel(KHZ_XTAL_CLK_SEL);
151 #endif // SI91X_32kHz_EXTERNAL_OSCILLATOR
152 
153   /* Configuring RC-MHz Clock for HF-FSM */
154   RSI_PS_FsmHfClkSel(FSM_MHZ_RC);
155 
156   /* XTAL control pointed to Software and  XTAL is Turned-Off from M4 */
157   RSI_ConfigXtal(XTAL_DISABLE_FROM_M4, XTAL_IS_IN_SW_CTRL_FROM_M4);
158 
159 #if ((defined SLI_SI91X_MCU_COMMON_FLASH_MODE) && (!(defined(RAM_COMPILATION))))
160   /* Before NWP is going to power save mode ,set m4ss_ref_clk_mux_ctrl ,
161           tass_ref_clk_mux_ctrl, AON domain power supply controls from NWP to M4 */
162   RSI_Set_Cntrls_To_M4();
163 
164 #endif
165 #if defined(SLI_SI915)
166   ULP_SPI_MEM_MAP(BG_LDO_REG1) |= BIT(LDO_0P6_BYPASS_BIT); //bypassing the retention LDO
167 #endif
168   /*Update the system clock sources with source generating frequency*/
169   system_clocks.m4ss_ref_clk     = DEFAULT_40MHZ_CLOCK;
170   system_clocks.ulpss_ref_clk    = DEFAULT_40MHZ_CLOCK;
171   system_clocks.soc_pll_clock    = DEFAULT_SOC_PLL_CLOCK;
172   system_clocks.modem_pll_clock  = DEFAULT_MODEM_PLL_CLOCK;
173   system_clocks.modem_pll_clock2 = DEFAULT_MODEM_PLL_CLOCK;
174   system_clocks.intf_pll_clock   = DEFAULT_INTF_PLL_CLOCK;
175   system_clocks.soc_clock        = DEFAULT_40MHZ_CLOCK;
176   system_clocks.rc_32khz_clock   = DEFAULT_32KHZ_RC_CLOCK;
177   system_clocks.rc_mhz_clock     = DEFAULT_MHZ_RC_CLOCK;
178   system_clocks.ro_20mhz_clock   = DEFAULT_20MHZ_RO_CLOCK;
179   system_clocks.ro_32khz_clock   = DEFAULT_32KHZ_RO_CLOCK;
180   system_clocks.xtal_32khz_clock = DEFAULT_32KHZ_XTAL_CLOCK;
181   system_clocks.doubler_clock    = DEFAULT_DOUBLER_CLOCK;
182   system_clocks.rf_ref_clock     = DEFAULT_40MHZ_CLOCK;
183   system_clocks.mems_ref_clock   = DEFAULT_MEMS_REF_CLOCK;
184   system_clocks.byp_rc_ref_clock = DEFAULT_MHZ_RC_CLOCK;
185   system_clocks.i2s_pll_clock    = DEFAULT_I2S_PLL_CLOCK;
186 
187   return;
188 }
189 
190 /**
191  * @fn       void fpuInit(void)
192  * @brief    This API is used to Early initialization of the FPU
193  * @return   none
194  *
195  */
fpuInit(void)196 void fpuInit(void)
197 {
198 #if __FPU_PRESENT != 0
199   // from arm trm manual:
200   //                ; CPACR is located at address 0xE000ED88
201   //                LDR.W R0, =0xE000ED88
202   //                ; Read CPACR
203   //                LDR R1, [R0]
204   //                ; Set bits 20-23 to enable CP10 and CP11 coprocessors
205   //                ORR R1, R1, #(0xF << 20)
206   //                ; Write back the modified value to the CPACR
207   //                STR R1, [R0]
208 
209   volatile uint32_t *regCpacr       = (uint32_t *)FPU_CPACR;
210   volatile const uint32_t *regMvfr0 = (volatile const uint32_t *)SCB_MVFR0;
211   volatile const uint32_t *regMvfr1 = (volatile const uint32_t *)SCB_MVFR1;
212   volatile uint32_t Cpacr;
213   volatile uint32_t Mvfr0;
214   volatile uint32_t Mvfr1;
215   char vfpPresent = 0;
216 
217   Mvfr0 = *regMvfr0;
218   Mvfr1 = *regMvfr1;
219 
220   vfpPresent = ((SCB_MVFR0_RESET == Mvfr0) && (SCB_MVFR1_RESET == Mvfr1));
221 
222   if (vfpPresent) {
223     Cpacr = *regCpacr;
224     Cpacr |= (0xF << 20);
225     *regCpacr = Cpacr; // enable CP10 and CP11 for full access
226   }
227 #endif /* __FPU_PRESENT != 0 */
228 }
229 
230 /**
231  * @fn     void SystemInit (void)
232  * @brief  This API is used Setup the RS1xxxx chip(Initialize the system)
233  * @return none
234  */
SystemInit(void)235 void SystemInit(void)
236 {
237   volatile uint32_t ipmuDummyRead = 0;
238   volatile uint32_t spareReg2     = 0;
239 
240   /*IPMU dummy read to make IPMU block out of RESET*/
241   ipmuDummyRead = ULP_SPI_MEM_MAP(0x144);
242   ipmuDummyRead = ipmuDummyRead;
243 
244   /*Update the REG Access SPI division factor to increase the SPI read/write speed*/
245   RSI_SetRegSpiDivision(0U);
246 
247   ULP_SPI_MEM_MAP(BG_SCDC_PROG_REG_1) &= REF_SEL_LP_DCDC;
248 
249   /*Spare register write sequence*/
250   spareReg2              = ULP_SPI_MEM_MAP(0x1C1);
251   ULP_SPI_MEM_MAP(0x141) = spareReg2;
252   //while(GSPI_CTRL_REG1 & SPI_ACTIVE);
253   /*Spare register write sequence*/
254   spareReg2              = ULP_SPI_MEM_MAP(0x1C0);
255   ULP_SPI_MEM_MAP(0x140) = spareReg2;
256 
257   /*Set IPMU BITS*/
258   ULP_SPI_MEM_MAP(SELECT_BG_CLK) |= (LATCH_TOP_SPI | LATCH_TRANSPARENT_HF | LATCH_TRANSPARENT_LF);
259 
260   while (GSPI_CTRL_REG1 & SPI_ACTIVE)
261     ;
262 
263   MCU_AON->MCUAON_GEN_CTRLS_b.ENABLE_PDO      = 1;
264   MCU_AON->MCUAON_GEN_CTRLS_b.NPSS_SUPPLY_0P9 = 0;
265 
266   /*Enable FPU*/
267   fpuInit();
268 
269   /* Enable REF Clock Control*/
270   //FIXME: This will be configured by boot-loader based on product mode
271   *(volatile uint32_t *)0x41300004 = BIT(24);
272 
273   /*Moving to BG sampling mode */
274   *(volatile uint32_t *)0x24048140 = (BIT(19) | BIT(1) | BIT(0));
275 
276   /*Disable WIC based wake up */
277   MCU_FSM->MCU_FSM_PERI_CONFIG_REG_b.WICENREQ = 0;
278 
279   /*Set ulp_wakeup_por*/
280   MCU_AON->MCUAON_KHZ_CLK_SEL_POR_RESET_STATUS_b.MCU_FIRST_POWERUP_POR     = 1U;
281   MCU_AON->MCUAON_KHZ_CLK_SEL_POR_RESET_STATUS_b.MCU_FIRST_POWERUP_RESET_N = 1U;
282   /*Programmable delay 4mes for WDT reset */
283   PMU_DIRECT_ACCESS(BG_SLEEP_TIMER_REG_OFFSET) |= BIT(19); //bgs_active_timer_sel
284   /*Programmable delay 4mes for WDT reset */
285   MCU_AON->MCUAON_SHELF_MODE_b.SHELF_MODE_WAKEUP_DELAY = 0x7;
286   /* Enables software based control of isolation and reset for ULP AON */
287   BATT_FF->M4SS_BYPASS_PWRCTRL_REG1_b.BYPASS_M4SS_PWRCTL_ULP_AON_b = 1;
288   /* Enables software based control of isolation and reset for M4ss CORE */
289   BATT_FF->M4SS_BYPASS_PWRCTRL_REG1_b.BYPASS_M4SS_PWRCTL_ULP_M4_CORE_b = 1;
290   return;
291 }
292 /**
293  *@}
294  */
295