1 /*
2  * Copyright (c) 2022 STMicroelectronics
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 #include <zephyr/kernel.h>
7 #include <zephyr/pm/pm.h>
8 #include <soc.h>
9 #include <zephyr/init.h>
10 #include <zephyr/arch/common/pm_s2ram.h>
11 #include <zephyr/drivers/timer/system_timer.h>
12 
13 #include <stm32wbaxx_ll_bus.h>
14 #include <stm32wbaxx_ll_cortex.h>
15 #include <stm32wbaxx_ll_pwr.h>
16 #include <stm32wbaxx_ll_icache.h>
17 #include <stm32wbaxx_ll_rcc.h>
18 #include <stm32wbaxx_ll_system.h>
19 #include <clock_control/clock_stm32_ll_common.h>
20 
21 #ifdef CONFIG_BT_STM32WBA
22 #include "scm.h"
23 #endif
24 
25 #include <zephyr/logging/log.h>
26 
27 LOG_MODULE_DECLARE(soc, CONFIG_SOC_LOG_LEVEL);
28 
29 void stm32_power_init(void);
30 
disable_cache(void)31 static void disable_cache(void)
32 {
33 	/* Disabling ICACHE */
34 	LL_ICACHE_Disable();
35 	while (LL_ICACHE_IsEnabled() == 1U) {
36 	}
37 
38 	/* Wait until ICACHE_SR.BUSYF is cleared */
39 	while (LL_ICACHE_IsActiveFlag_BUSY() == 1U) {
40 	}
41 
42 	/* Wait until ICACHE_SR.BSYENDF is set */
43 	while (LL_ICACHE_IsActiveFlag_BSYEND() == 0U) {
44 	}
45 }
46 
set_mode_stop(uint8_t substate_id)47 static void set_mode_stop(uint8_t substate_id)
48 {
49 
50 	LL_PWR_ClearFlag_STOP();
51 	LL_RCC_ClearResetFlags();
52 
53 	/* Erratum 2.2.15:
54 	 * Disabling ICACHE is required before entering stop mode
55 	 */
56 	disable_cache();
57 
58 #ifdef CONFIG_BT_STM32WBA
59 	scm_setwaitstates(LP);
60 #endif
61 	/* Set SLEEPDEEP bit of Cortex System Control Register */
62 	LL_LPM_EnableDeepSleep();
63 
64 	while (LL_PWR_IsActiveFlag_ACTVOS() == 0) {
65 	}
66 
67 	switch (substate_id) {
68 	case 1: /* enter STOP0 mode */
69 		LL_PWR_SetPowerMode(LL_PWR_MODE_STOP0);
70 		break;
71 	case 2: /* enter STOP1 mode */
72 		LL_PWR_SetPowerMode(LL_PWR_MODE_STOP1);
73 		break;
74 	default:
75 		LOG_DBG("Unsupported power state substate-id %u", substate_id);
76 		break;
77 	}
78 }
79 
80 #if defined(CONFIG_PM_S2RAM)
suspend_to_ram(void)81 static int suspend_to_ram(void)
82 {
83 	LL_LPM_EnableDeepSleep();
84 
85 	while (LL_PWR_IsActiveFlag_ACTVOS() == 0) {
86 	}
87 
88 	/* Select mode entry : WFE or WFI and enter the CPU selected mode */
89 	k_cpu_idle();
90 
91 	return 0;
92 }
93 
set_mode_suspend_to_ram(void)94 static void set_mode_suspend_to_ram(void)
95 {
96 	/* Enable SRAM full retention */
97 	LL_PWR_SetSRAM1SBRetention(LL_PWR_SRAM1_SB_FULL_RETENTION);
98 	LL_PWR_SetSRAM2SBRetention(LL_PWR_SRAM2_SB_FULL_RETENTION);
99 
100 	/* Enable RTC wakeup
101 	 * This configures an internal pin that generates an event to wakeup the system
102 	 */
103 	LL_PWR_EnableWakeUpPin(LL_PWR_WAKEUP_PIN7);
104 	LL_PWR_SetWakeUpPinSignal3Selection(LL_PWR_WAKEUP_PIN7);
105 
106 	/* Clear flags */
107 	LL_PWR_ClearFlag_SB();
108 	LL_PWR_ClearFlag_WU();
109 	LL_RCC_ClearResetFlags();
110 
111 	disable_cache();
112 
113 	/* Select standby mode */
114 	LL_PWR_SetPowerMode(LL_PWR_MODE_STANDBY);
115 
116 	/* Save context and enter Standby mode */
117 	arch_pm_s2ram_suspend(suspend_to_ram);
118 
119 	/* Execution is restored at this point after wake up */
120 	/* Restore system clock as soon as we exit standby mode */
121 	stm32_clock_control_standby_exit();
122 }
123 #endif
124 
125 /* Invoke Low Power/System Off specific Tasks */
pm_state_set(enum pm_state state,uint8_t substate_id)126 void pm_state_set(enum pm_state state, uint8_t substate_id)
127 {
128 	switch (state) {
129 	case PM_STATE_SUSPEND_TO_IDLE:
130 		set_mode_stop(substate_id);
131 
132 		/* Select mode entry : WFE or WFI and enter the CPU selected mode */
133 		k_cpu_idle();
134 
135 		break;
136 #if defined(CONFIG_PM_S2RAM)
137 	case PM_STATE_SUSPEND_TO_RAM:
138 		set_mode_suspend_to_ram();
139 		break;
140 #endif
141 	default:
142 		LOG_DBG("Unsupported power state %u", state);
143 		return;
144 	}
145 }
146 
147 /* Handle SOC specific activity after Low Power Mode Exit */
pm_state_exit_post_ops(enum pm_state state,uint8_t substate_id)148 void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id)
149 {
150 #ifdef CONFIG_BT_STM32WBA
151 	if (LL_PWR_IsActiveFlag_STOP() == 1U) {
152 		scm_setup();
153 	} else {
154 		scm_setwaitstates(RUN);
155 	}
156 #endif
157 
158 	switch (state) {
159 	case PM_STATE_SUSPEND_TO_IDLE:
160 		if (substate_id <= 2) {
161 			/* Erratum 2.2.15:
162 			 * Enable ICACHE when exiting stop mode
163 			 */
164 			LL_ICACHE_SetMode(LL_ICACHE_1WAY);
165 			LL_ICACHE_Enable();
166 			while (LL_ICACHE_IsEnabled() == 0U) {
167 			}
168 
169 			LL_LPM_DisableSleepOnExit();
170 			LL_LPM_EnableSleep();
171 		} else {
172 			LOG_DBG("Unsupported power substate-id %u",
173 							substate_id);
174 		}
175 		break;
176 	case PM_STATE_SUSPEND_TO_RAM:
177 #if defined(CONFIG_PM_S2RAM)
178 		stm32wba_init();
179 		stm32_power_init();
180 
181 		LL_LPM_DisableSleepOnExit();
182 		LL_LPM_EnableSleep();
183 #else
184 		LOG_DBG("Suspend to RAM needs CONFIG_PM_S2RAM to be enabled");
185 #endif
186 		break;
187 	case PM_STATE_STANDBY:
188 		__fallthrough;
189 	case PM_STATE_SUSPEND_TO_DISK:
190 		__fallthrough;
191 	default:
192 		LOG_DBG("Unsupported power state %u", state);
193 		break;
194 	}
195 
196 	/* When BLE is enabled, clock restoration is performed by SCM */
197 #if !defined(CONFIG_BT_STM32WBA)
198 	stm32_clock_control_init(NULL);
199 #endif
200 
201 	/*
202 	 * System is now in active mode.
203 	 * Reenable interrupts which were disabled
204 	 * when OS started idling code.
205 	 */
206 	irq_unlock(0);
207 }
208 
209 /* Initialize STM32 Power */
stm32_power_init(void)210 void stm32_power_init(void)
211 {
212 
213 #ifdef CONFIG_BT_STM32WBA
214 	scm_init();
215 #endif
216 
217 	LL_AHB4_GRP1_EnableClock(LL_AHB4_GRP1_PERIPH_PWR);
218 
219 #ifdef CONFIG_DEBUG
220 	LL_DBGMCU_EnableDBGStandbyMode();
221 	LL_DBGMCU_APB7_GRP1_FreezePeriph(LL_DBGMCU_APB7_GRP1_RTC_STOP);
222 	LL_DBGMCU_APB7_GRP1_FreezePeriph(LL_DBGMCU_APB7_GRP1_LPTIM1_STOP);
223 #else
224 	LL_DBGMCU_DisableDBGStandbyMode();
225 #endif
226 
227 	/* Enabling  Ultra Low power mode */
228 	LL_PWR_EnableUltraLowPowerMode();
229 
230 	LL_FLASH_EnableSleepPowerDown();
231 }
232