1 /*
2 * Copyright (c) 2020 - 2024 Renesas Electronics Corporation and/or its affiliates
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 /***********************************************************************************************************************
8 * Includes
9 **********************************************************************************************************************/
10
11 #include "bsp_api.h"
12 #include "r_lpm.h"
13
14 /***********************************************************************************************************************
15 * Macro definitions
16 **********************************************************************************************************************/
17
18 #define LPM_LPSCR_SYSTEM_ACTIVE (0x0U)
19 #define LPM_LPSCR_SOFTWARE_STANDBY_MODE (0x4U)
20 #define LPM_LPSCR_DEEP_SOFTWARE_STANDBY_MODE1 (0x8U)
21 #define LPM_LPSCR_DEEP_SOFTWARE_STANDBY_MODE2 (0x9U)
22 #define LPM_LPSCR_DEEP_SOFTWARE_STANDBY_MODE3 (0xAU)
23
24 /* Clock control register addresses */
25 #define LPM_CLOCK_HOCOCR (&R_SYSTEM->HOCOCR)
26 #define LPM_CLOCK_MOCOCR (&R_SYSTEM->MOCOCR)
27 #define LPM_CLOCK_LOCOCR (&R_SYSTEM->LOCOCR)
28 #define LPM_CLOCK_MOSCCR (&R_SYSTEM->MOSCCR)
29 #define LPM_CLOCK_SOSCCR (&R_SYSTEM->SOSCCR)
30 #define LPM_CLOCK_PLLCR (&R_SYSTEM->PLLCR)
31 #define LPM_CLOCK_PLL2CR (&R_SYSTEM->PLL2CR)
32 #define LPM_CLOCK_HOCO 0 // The high speed on chip oscillator.
33 #define LPM_CLOCK_MOCO 1 // The middle speed on chip oscillator.
34 #define LPM_CLOCK_LOCO 2 // The low speed on chip oscillator.
35 #define LPM_CLOCK_MAIN_OSC 3 // The main oscillator.
36 #define LPM_CLOCK_SUBCLOCK 4 // The subclock oscillator.
37 #define LPM_CLOCK_PLL 5 // The PLL oscillator.
38 #define LPM_CLOCK_PLL2 6 // The PLL2 oscillator.
39
40 /* From user's manual and discussions with hardware group,
41 * using the maximum is safe for all MCUs, will be updated and restored in LPM when entering
42 * low power mode on RA6 MCUs (lowPowerModeEnter())
43 */
44
45 #define LPM_SW_STANDBY_STCONR (0x0U)
46 #define LPM_SW_STANDBY_WAKE_STCONR (0x3U)
47
48 #define LPM_SNZREQCR1_OFFSET (32ULL)
49 #define LPM_WUPEN1_OFFSET (32ULL)
50 #define LPM_SBYEDCR1_OFFSET (32ULL)
51
52 #define LPM_OPEN (0x524c504d)
53
54 /***********************************************************************************************************************
55 * Typedef definitions
56 **********************************************************************************************************************/
57
58 /***********************************************************************************************************************
59 * Private global variables
60 **********************************************************************************************************************/
61
62 #ifdef R_SYSTEM_SNZCR_SNZE_Msk
63
64 /* This array stores the address of the register containing the stop bit for each clock. All of these registers are
65 * 8-bit registers and only bit 0 is valid. All other bits are read as 0 and should be written to 0. Bit 0 of each
66 * of these registers indicates that the corresponding clock is stopped when set, or that the corresponding clock
67 * is operating when cleared. */
68 static uint8_t volatile * const gp_lpm_clock_stp_registers[] =
69 {
70 [LPM_CLOCK_HOCO] = LPM_CLOCK_HOCOCR,
71 [LPM_CLOCK_MOCO] = LPM_CLOCK_MOCOCR,
72 [LPM_CLOCK_LOCO] = LPM_CLOCK_LOCOCR,
73 [LPM_CLOCK_MAIN_OSC] = LPM_CLOCK_MOSCCR,
74 [LPM_CLOCK_SUBCLOCK] = LPM_CLOCK_SOSCCR,
75 #if BSP_FEATURE_CGC_HAS_PLL
76 [LPM_CLOCK_PLL] = LPM_CLOCK_PLLCR,
77 #endif
78 #if BSP_FEATURE_CGC_HAS_PLL2
79 [LPM_CLOCK_PLL2] = LPM_CLOCK_PLL2CR,
80 #endif
81 };
82 #endif
83
84 /***********************************************************************************************************************
85 * Global Variables
86 **********************************************************************************************************************/
87 const lpm_api_t g_lpm_on_lpm =
88 {
89 .open = R_LPM_Open,
90 .close = R_LPM_Close,
91 .lowPowerReconfigure = R_LPM_LowPowerReconfigure,
92 .lowPowerModeEnter = R_LPM_LowPowerModeEnter,
93 .ioKeepClear = R_LPM_IoKeepClear,
94 };
95
96 /***********************************************************************************************************************
97 * Functions
98 **********************************************************************************************************************/
99
100 /***********************************************************************************************************************
101 * Private Functions
102 **********************************************************************************************************************/
103 static fsp_err_t r_lpm_configure(lpm_cfg_t const * const p_cfg);
104 static fsp_err_t r_lpm_low_power_enter(lpm_instance_ctrl_t * const p_instance_ctrl);
105
106 #ifdef R_SYSTEM_SNZCR_SNZE_Msk
107 static fsp_err_t r_lpm_check_clocks(uint32_t clock_source);
108
109 #endif
110 static void r_lpm_wait_for_operating_mode_flags(void);
111
112 #if BSP_FEATURE_LPM_HAS_LPSCR
113 static uint8_t r_lpm_lpscr_calculate(lpm_cfg_t const * p_cfg);
114
115 #endif
116 #if LPM_CFG_PARAM_CHECKING_ENABLE
117 static fsp_err_t r_lpm_mcu_specific_low_power_check(lpm_cfg_t const * const p_cfg);
118
119 #endif
120
121 /*******************************************************************************************************************//**
122 * @addtogroup LPM
123 * @{
124 **********************************************************************************************************************/
125
126 /*******************************************************************************************************************//**
127 * Perform any necessary initialization
128 *
129 * @retval FSP_SUCCESS LPM instance opened
130 * @retval FSP_ERR_ASSERTION Null Pointer
131 * @retval FSP_ERR_ALREADY_OPEN LPM instance is already open
132 * @retval FSP_ERR_UNSUPPORTED This MCU does not support Deep Software Standby
133 * @retval FSP_ERR_INVALID_ARGUMENT One of the following:
134 * - Invalid snooze entry source
135 * - Invalid snooze end sources
136 * @retval FSP_ERR_INVALID_MODE One of the following:
137 * - Invalid low power mode
138 * - Invalid DTC option for snooze mode
139 * - Invalid deep standby end sources
140 * - Invalid deep standby end sources edges
141 * - Invalid power supply option for deep standby
142 * - Invalid IO port option for deep standby
143 * - Invalid output port state setting for standby or deep standby
144 * - Invalid sources for wake from standby mode
145 * - Invalid power supply option for standby
146 * - Invalid IO port option for standby
147 * - Invalid standby end sources
148 * - Invalid standby end sources edges
149 **********************************************************************************************************************/
R_LPM_Open(lpm_ctrl_t * const p_api_ctrl,lpm_cfg_t const * const p_cfg)150 fsp_err_t R_LPM_Open (lpm_ctrl_t * const p_api_ctrl, lpm_cfg_t const * const p_cfg)
151 {
152 lpm_instance_ctrl_t * p_ctrl = (lpm_instance_ctrl_t *) p_api_ctrl;
153 #if LPM_CFG_PARAM_CHECKING_ENABLE
154 FSP_ASSERT(NULL != p_api_ctrl);
155 FSP_ERROR_RETURN(LPM_OPEN != p_ctrl->lpm_open, FSP_ERR_ALREADY_OPEN);
156 #endif
157
158 /* Save the configuration */
159 p_ctrl->p_cfg = p_cfg;
160
161 fsp_err_t err = r_lpm_configure(p_cfg);
162 FSP_ERROR_RETURN(FSP_SUCCESS == err, err);
163
164 p_ctrl->lpm_open = LPM_OPEN;
165
166 return FSP_SUCCESS;
167 }
168
169 /*******************************************************************************************************************//**
170 * Configure a low power mode
171 *
172 * NOTE: This function does not enter the low power mode, it only configures parameters of the mode. Execution of the
173 * WFI instruction is what causes the low power mode to be entered.
174 *
175 * @retval FSP_SUCCESS Low power mode successfuly applied
176 * @retval FSP_ERR_ASSERTION Null Pointer
177 * @retval FSP_ERR_NOT_OPEN LPM instance is not open
178 * @retval FSP_ERR_UNSUPPORTED This MCU does not support Deep Software Standby
179 * @retval FSP_ERR_INVALID_ARGUMENT One of the following:
180 * - Invalid snooze entry source
181 * - Invalid snooze end sources
182 * @retval FSP_ERR_INVALID_MODE One of the following:
183 * - Invalid low power mode
184 * - Invalid DTC option for snooze mode
185 * - Invalid deep standby end sources
186 * - Invalid deep standby end sources edges
187 * - Invalid power supply option for deep standby
188 * - Invalid IO port option for deep standby
189 * - Invalid output port state setting for standby or deep standby
190 * - Invalid sources for wake from standby mode
191 * - Invalid power supply option for standby
192 * - Invalid IO port option for standby
193 * - Invalid standby end sources
194 * - Invalid standby end sources edges
195 **********************************************************************************************************************/
R_LPM_LowPowerReconfigure(lpm_ctrl_t * const p_api_ctrl,lpm_cfg_t const * const p_cfg)196 fsp_err_t R_LPM_LowPowerReconfigure (lpm_ctrl_t * const p_api_ctrl, lpm_cfg_t const * const p_cfg)
197 {
198 lpm_instance_ctrl_t * p_ctrl = (lpm_instance_ctrl_t *) p_api_ctrl;
199
200 #if LPM_CFG_PARAM_CHECKING_ENABLE
201 FSP_ASSERT(NULL != p_api_ctrl);
202 FSP_ERROR_RETURN(LPM_OPEN == p_ctrl->lpm_open, FSP_ERR_NOT_OPEN);
203 #endif
204
205 /* Save the configuration */
206 p_ctrl->p_cfg = p_cfg;
207
208 return r_lpm_configure(p_cfg);
209 }
210
211 /*******************************************************************************************************************//**
212 * Enter low power mode (sleep/deep sleep/standby/deep standby) using WFI macro.
213 *
214 * Function will return after waking from low power mode.
215 *
216 * @retval FSP_SUCCESS Successful.
217 * @retval FSP_ERR_ASSERTION Null pointer.
218 * @retval FSP_ERR_NOT_OPEN LPM instance is not open
219 * @retval FSP_ERR_INVALID_MODE One of the following:
220 * - HOCO was not system clock when using snooze mode with SCI0/RXD0.
221 * - HOCO was not stable when using snooze mode with SCI0/RXD0.
222 * - MOCO was running when using snooze mode with SCI0/RXD0.
223 * - MAIN OSCILLATOR was running when using snooze mode with SCI0/RXD0.
224 * - PLL was running when using snooze mode with SCI0/RXD0.
225 * - Unable to disable ocillator stop detect when using standby or deep standby.
226 **********************************************************************************************************************/
R_LPM_LowPowerModeEnter(lpm_ctrl_t * const p_api_ctrl)227 fsp_err_t R_LPM_LowPowerModeEnter (lpm_ctrl_t * const p_api_ctrl)
228 {
229 lpm_instance_ctrl_t * p_ctrl = (lpm_instance_ctrl_t *) p_api_ctrl;
230 #if LPM_CFG_PARAM_CHECKING_ENABLE
231 FSP_ASSERT(NULL != p_ctrl);
232 FSP_ERROR_RETURN(LPM_OPEN == p_ctrl->lpm_open, FSP_ERR_NOT_OPEN);
233
234 #if BSP_FEATURE_LPM_STANDBY_MOCO_REQUIRED
235
236 /* The MOCO must be running when entering standby mode. */
237 if (LPM_MODE_STANDBY <= p_ctrl->p_cfg->low_power_mode)
238 {
239 FSP_ERROR_RETURN(0 == FSP_STYPE3_REG8_READ(R_SYSTEM->MOCOCR, !R_SYSTEM->CGFSAR_b.NONSEC03),
240 FSP_ERR_INVALID_MODE);
241 }
242 #endif
243 #endif
244 #if BSP_FEATURE_LPM_SNOOZE_REQUEST_DTCST_DTCST == 1
245 uint8_t saved_dtcst = 0;
246 #endif
247
248 /* Wait for ongoing operating mode transition (OPCMTSF, SOPCMTSF) */
249 r_lpm_wait_for_operating_mode_flags();
250
251 /* Must enable writing to Low Power Mode register prior to entering Low Power Mode. */
252 R_BSP_RegisterProtectDisable(BSP_REG_PROTECT_OM_LPC_BATT);
253 #if LPM_CFG_STANDBY_LIMIT
254 #if BSP_FEATURE_LPM_HAS_LPSCR
255 R_SYSTEM->LPSCR = r_lpm_lpscr_calculate(p_ctrl->p_cfg);
256 #endif
257
258 #if BSP_FEATURE_LPM_HAS_SBYCR_SSBY
259 if (LPM_MODE_SLEEP != p_ctrl->p_cfg->low_power_mode)
260 {
261 R_SYSTEM->SBYCR |= (1U << R_SYSTEM_SBYCR_SSBY_Pos);
262 }
263 #endif
264 #endif
265 #if BSP_FEATURE_LPM_HAS_SNOOZE
266 if (LPM_MODE_STANDBY_SNOOZE == p_ctrl->p_cfg->low_power_mode)
267 {
268 /* Configure Snooze registers */
269 #if BSP_FEATURE_LPM_SNOOZE_REQUEST_DTCST_DTCST == 1
270 if (!p_ctrl->p_cfg->dtc_state_in_snooze)
271 {
272 #if LPM_CFG_PARAM_CHECKING_ENABLE
273 FSP_ERROR_RETURN(0 == R_MSTP->MSTPCRA_b.MSTPA22, FSP_ERR_INVALID_MODE);
274 #endif
275
276 /* Store the previous state of DTCST. */
277 saved_dtcst = R_DTC->DTCST;
278
279 /* If snooze mode does not use DTC, DTC should be stopped before entering snooze mode. */
280 R_DTC->DTCST = 0U;
281 }
282 #endif
283 }
284 #endif
285 fsp_err_t err = r_lpm_low_power_enter(p_ctrl);
286
287 #if LPM_CFG_STANDBY_LIMIT
288 #if BSP_FEATURE_LPM_HAS_LPSCR
289 if ((LPM_MODE_SLEEP != p_ctrl->p_cfg->low_power_mode) && (LPM_MODE_DEEP_SLEEP != p_ctrl->p_cfg->low_power_mode))
290 {
291 R_SYSTEM->LPSCR = 0;
292 }
293 #endif
294 #if BSP_FEATURE_LPM_HAS_SBYCR_SSBY
295 if (LPM_MODE_SLEEP != p_ctrl->p_cfg->low_power_mode)
296 {
297 R_SYSTEM->SBYCR &= (uint16_t) (~(1U << R_SYSTEM_SBYCR_SSBY_Pos));
298 }
299 #endif
300 #endif
301 #if BSP_FEATURE_LPM_HAS_SNOOZE
302 if (LPM_MODE_STANDBY_SNOOZE == p_ctrl->p_cfg->low_power_mode)
303 {
304 #if BSP_FEATURE_LPM_SNOOZE_REQUEST_DTCST_DTCST == 1
305 if (!p_ctrl->p_cfg->dtc_state_in_snooze)
306 {
307 /* If DTC was stopped prior to entering snooze mode, then start it again. */
308 R_DTC->DTCST = saved_dtcst;
309 }
310 #endif
311 }
312 #endif
313
314 R_BSP_RegisterProtectEnable(BSP_REG_PROTECT_OM_LPC_BATT);
315
316 return err;
317 }
318
319 /*******************************************************************************************************************//**
320 * Clear the IOKEEP bit after deep software standby
321 *
322 * @retval FSP_SUCCESS DPSBYCR_b.IOKEEP bit cleared Successfully.
323 * @retval FSP_ERR_UNSUPPORTED Deep standby mode not supported on this MCU.
324 **********************************************************************************************************************/
R_LPM_IoKeepClear(lpm_ctrl_t * const p_api_ctrl)325 fsp_err_t R_LPM_IoKeepClear (lpm_ctrl_t * const p_api_ctrl)
326 {
327 FSP_PARAMETER_NOT_USED(p_api_ctrl);
328 #if BSP_FEATURE_LPM_HAS_DEEP_STANDBY
329 R_BSP_RegisterProtectDisable(BSP_REG_PROTECT_OM_LPC_BATT);
330
331 R_SYSTEM->DPSBYCR_b.IOKEEP = 0U;
332
333 R_BSP_RegisterProtectEnable(BSP_REG_PROTECT_OM_LPC_BATT);
334
335 return FSP_SUCCESS;
336 #else
337
338 return FSP_ERR_UNSUPPORTED;
339 #endif
340 }
341
342 /*******************************************************************************************************************//**
343 * Close the LPM Instance
344 *
345 * @retval FSP_SUCCESS LPM driver closed
346 * @retval FSP_ERR_NOT_OPEN LPM instance is not open
347 * @retval FSP_ERR_ASSERTION Null Pointer
348 **********************************************************************************************************************/
R_LPM_Close(lpm_ctrl_t * const p_api_ctrl)349 fsp_err_t R_LPM_Close (lpm_ctrl_t * const p_api_ctrl)
350 {
351 lpm_instance_ctrl_t * p_ctrl = (lpm_instance_ctrl_t *) p_api_ctrl;
352 #if LPM_CFG_PARAM_CHECKING_ENABLE
353 FSP_ASSERT(NULL != p_api_ctrl);
354 FSP_ERROR_RETURN(LPM_OPEN == p_ctrl->lpm_open, FSP_ERR_NOT_OPEN);
355 #endif
356
357 p_ctrl->lpm_open = 0;
358
359 return FSP_SUCCESS;
360 }
361
362 /*******************************************************************************************************************//**
363 * @} (end addtogroup LPM)
364 **********************************************************************************************************************/
365
366 #if LPM_CFG_PARAM_CHECKING_ENABLE
367
368 /*******************************************************************************************************************//**
369 * Verifies all MCU specific settings related to low power modes
370 * @param p_cfg the MCU specific configuration
371 *
372 * @retval FSP_SUCCESS Configuration is valid
373 * @retval FSP_ERR_UNSUPPORTED This MCU does not support Deep Software Standby
374 * @retval FSP_ERR_INVALID_ARGUMENT One of the following:
375 * - Invalid snooze entry source
376 * - Invalid snooze end sources
377 * @retval FSP_ERR_INVALID_MODE One of the following:
378 * - Invalid low power mode
379 * - Invalid DTC option for snooze mode
380 * - Invalid deep standby end sources
381 * - Invalid deep standby end sources edges
382 * - Invalid power supply option for deep standby
383 * - Invalid IO port option for deep standby
384 * - Invalid output port state setting for standby or deep standby
385 * - Invalid sources for wake from standby mode
386 * - Invalid power supply option for standby
387 * - Invalid IO port option for standby
388 * - Invalid standby end sources
389 * - Invalid standby end sources edges
390 *
391 * @note This function assumes the register has been unlocked by the calling application
392 **********************************************************************************************************************/
r_lpm_mcu_specific_low_power_check(lpm_cfg_t const * const p_cfg)393 fsp_err_t r_lpm_mcu_specific_low_power_check (lpm_cfg_t const * const p_cfg)
394 {
395 #if !BSP_FEATURE_LPM_HAS_DEEP_SLEEP
396 FSP_ERROR_RETURN(LPM_MODE_DEEP_SLEEP != p_cfg->low_power_mode, FSP_ERR_UNSUPPORTED)
397 #endif
398 #if !BSP_FEATURE_LPM_HAS_SNOOZE
399 FSP_ERROR_RETURN(LPM_MODE_STANDBY_SNOOZE != p_cfg->low_power_mode, FSP_ERR_UNSUPPORTED)
400 #endif
401
402 #if BSP_FEATURE_LPM_HAS_DEEP_SLEEP
403 if ((LPM_MODE_SLEEP != p_cfg->low_power_mode) && (LPM_MODE_DEEP_SLEEP != p_cfg->low_power_mode))
404 #else
405 if (LPM_MODE_SLEEP != p_cfg->low_power_mode)
406 #endif
407 {
408 if (LPM_MODE_STANDBY_SNOOZE == p_cfg->low_power_mode)
409 {
410 #if BSP_FEATURE_LPM_HAS_SNOOZE
411 #if BSP_FEATURE_LPM_SNZREQCR_MASK
412 FSP_ERROR_RETURN(0U == ((uint64_t) p_cfg->snooze_request_source & (~BSP_FEATURE_LPM_SNZREQCR_MASK)),
413 FSP_ERR_INVALID_ARGUMENT);
414 #endif
415 #if BSP_FEATURE_LPM_SNZEDCR_MASK > 0
416 FSP_ERROR_RETURN(0U == ((uint32_t) p_cfg->snooze_end_sources & (~BSP_FEATURE_LPM_SNZEDCR_MASK)),
417 FSP_ERR_INVALID_ARGUMENT);
418 #endif
419 #endif
420 }
421 else if (LPM_MODE_DEEP == p_cfg->low_power_mode)
422 {
423 #if BSP_FEATURE_LPM_HAS_DEEP_STANDBY
424
425 /* Verify the deep software standby interrupt source is valid. */
426 FSP_ERROR_RETURN(0U == (uint32_t) (~BSP_FEATURE_LPM_DPSIER_MASK & p_cfg->deep_standby_cancel_source),
427 FSP_ERR_INVALID_MODE);
428
429 /* Verify the deep software standby interrupt edge is valid. */
430 FSP_ERROR_RETURN(0U == (uint32_t) (~BSP_FEATURE_LPM_DPSIEGR_MASK & p_cfg->deep_standby_cancel_edge),
431 FSP_ERR_INVALID_MODE);
432
433 /* Verify all configured edges have a source configured. */
434 FSP_ERROR_RETURN(0U ==
435 (~p_cfg->deep_standby_cancel_source &
436 (lpm_deep_standby_cancel_source_t) p_cfg->deep_standby_cancel_edge),
437 FSP_ERR_INVALID_MODE);
438 #else
439
440 return FSP_ERR_UNSUPPORTED;
441 #endif
442 }
443 else
444 {
445 /* Do nothing. */
446 }
447
448 #if BSP_FEATURE_ICU_WUPEN_MASK > 0
449 FSP_ERROR_RETURN(0U == ((uint64_t) p_cfg->standby_wake_sources & ~BSP_FEATURE_ICU_WUPEN_MASK),
450 FSP_ERR_INVALID_MODE);
451 #endif
452 #if BSP_FEATURE_ICU_SBYEDCR_MASK
453 FSP_ERROR_RETURN(0U == ((uint64_t) p_cfg->standby_wake_sources & ~BSP_FEATURE_ICU_SBYEDCR_MASK),
454 FSP_ERR_INVALID_MODE);
455 #endif
456 }
457
458 #if BSP_FEATURE_LPM_HAS_HOCO_STARTUP_SPEED_MODE
459 FSP_ERROR_RETURN(((R_SYSTEM->FOCOSCR_b.CKSEL == 0) && (R_SYSTEM->FMAINSCR_b.CKSEL == 0) &&
460 (R_SYSTEM->ICLKSCR_b.CKSEL == 0) && (R_SYSTEM->HOCODIV == 0)),
461 FSP_ERR_INVALID_MODE);
462 #endif
463
464 return FSP_SUCCESS;
465 }
466
467 #endif
468
469 /*******************************************************************************************************************//**
470 * Configures all MCU specific settings related to low power modes
471 * @param p_cfg the MCU specific configuration
472 *
473 * @note This function assumes the register has been unlocked by the calling application
474 *
475 * @retval FSP_SUCCESS Configuration is valid
476 * @retval FSP_ERR_UNSUPPORTED This MCU does not support Deep Software Standby
477 * @retval FSP_ERR_ASSERTION NULL p_extend when low power mode is not Sleep
478 * @retval FSP_ERR_INVALID_ARGUMENT One of the following:
479 * - Invalid snooze entry source
480 * - Invalid snooze end sources
481 * @retval FSP_ERR_INVALID_MODE One of the following:
482 * - Invalid low power mode
483 * - Invalid DTC option for snooze mode
484 * - Invalid deep standby end sources
485 * - Invalid deep standby end sources edges
486 * - Invalid power supply option for deep standby
487 * - Invalid IO port option for deep standby
488 * - Invalid output port state setting for standby or deep standby
489 * - Invalid sources for wake from standby mode
490 * - Invalid power supply option for standby
491 * - Invalid IO port option for standby
492 * - Invalid standby end sources
493 * - Invalid standby end sources edges
494 **********************************************************************************************************************/
r_lpm_configure(lpm_cfg_t const * const p_cfg)495 fsp_err_t r_lpm_configure (lpm_cfg_t const * const p_cfg)
496 {
497 #if LPM_CFG_PARAM_CHECKING_ENABLE
498 FSP_ASSERT(NULL != p_cfg);
499 fsp_err_t err = r_lpm_mcu_specific_low_power_check(p_cfg);
500 FSP_ERROR_RETURN(FSP_SUCCESS == err, err);
501 #endif
502 #if BSP_FEATURE_ICU_SBYEDCR_MASK > 0
503 uint32_t sbyedcr0 = 0;
504 uint32_t sbyedcr1 = 0;
505 #endif
506 #ifdef R_SYSTEM_SNZCR_SNZE_Msk
507 uint32_t snzcr = 0;
508 #endif
509 uint32_t sbycr = 0;
510 #if BSP_FEATURE_LPM_HAS_DEEP_STANDBY
511 uint32_t dpsbycr = 0;
512 #endif
513
514 #if BSP_FEATURE_LPM_HAS_LDO_CONTROL
515 if ((R_SYSTEM->PLL1LDOCR_b.SKEEP != p_cfg->ldo_standby_cfg.pll1_ldo) ||
516 (R_SYSTEM->PLL2LDOCR_b.SKEEP != p_cfg->ldo_standby_cfg.pll2_ldo) ||
517 (R_SYSTEM->HOCOLDOCR_b.SKEEP != p_cfg->ldo_standby_cfg.hoco_ldo))
518 {
519 /* Writing to PLL1LDOCR, PLL2LDOCR and HOCOLDOCR registers is only allowed in High Speed Mode. */
520 FSP_ERROR_RETURN(R_SYSTEM->OPCCR_b.OPCM == 0, FSP_ERR_INVALID_MODE);
521 }
522 #endif
523
524 R_BSP_RegisterProtectDisable(BSP_REG_PROTECT_OM_LPC_BATT);
525
526 /* Wait for ongoing operating mode transition (OPCMTSF, SOPCMTSF) */
527 r_lpm_wait_for_operating_mode_flags();
528
529 /* Configure registers for modes other than Sleep */
530 if (LPM_MODE_SLEEP != p_cfg->low_power_mode)
531 {
532 #if BSP_FEATURE_LPM_HAS_DEEP_STANDBY
533
534 /* Configure Deep Software Standby registers. */
535 if (LPM_MODE_DEEP == p_cfg->low_power_mode)
536 {
537 R_SYSTEM->DPSIER0 = (uint8_t) (p_cfg->deep_standby_cancel_source);
538 R_SYSTEM->DPSIER1 = (uint8_t) (p_cfg->deep_standby_cancel_source >> 8U);
539 R_SYSTEM->DPSIER2 = (uint8_t) (p_cfg->deep_standby_cancel_source >> 16U);
540 R_SYSTEM->DPSIER3 = (uint8_t) (p_cfg->deep_standby_cancel_source >> 24U);
541
542 R_SYSTEM->DPSIEGR0 = (uint8_t) (p_cfg->deep_standby_cancel_edge);
543 R_SYSTEM->DPSIEGR1 = (uint8_t) (p_cfg->deep_standby_cancel_edge >> 8U);
544 R_SYSTEM->DPSIEGR2 = (uint8_t) (p_cfg->deep_standby_cancel_edge >> 16U);
545
546 #if BSP_FEATURE_LPM_HAS_DPSBYCR_DPSBY
547 dpsbycr |= R_SYSTEM_DPSBYCR_DPSBY_Msk;
548 #endif
549 #if BSP_FEATURE_LPM_HAS_DPSBYCR_DEEPCUT
550 dpsbycr |= ((uint32_t) p_cfg->power_supply_state << R_SYSTEM_DPSBYCR_DEEPCUT_Pos) &
551 R_SYSTEM_DPSBYCR_DEEPCUT_Msk;
552 #endif
553 dpsbycr |= ((uint32_t) p_cfg->io_port_state << R_SYSTEM_DPSBYCR_IOKEEP_Pos) & R_SYSTEM_DPSBYCR_IOKEEP_Msk;
554 }
555 #endif
556
557 #if BSP_FEATURE_LPM_HAS_SNOOZE
558
559 /* Configure Snooze registers */
560 if (LPM_MODE_STANDBY_SNOOZE == p_cfg->low_power_mode)
561 {
562 #if BSP_FEATURE_LPM_SNZREQCR_MASK > 0
563
564 /* Configure RXD0 falling edge detect */
565 if (LPM_SNOOZE_REQUEST_RXD0_FALLING == p_cfg->snooze_request_source)
566 {
567 snzcr = 1U << R_SYSTEM_SNZCR_RXDREQEN_Pos;
568 }
569
570 /* Set the request condition that can trigger entry in to snooze mode */
571 R_SYSTEM->SNZREQCR = (uint32_t) p_cfg->snooze_request_source & UINT32_MAX;
572 #endif
573 #if BSP_FEATURE_LPM_HAS_SNZREQCR1 == 1
574 R_SYSTEM->SNZREQCR1 = (uint32_t) (p_cfg->snooze_request_source >> LPM_SNZREQCR1_OFFSET) & UINT32_MAX;
575 #endif
576 #if BSP_FEATURE_LPM_HAS_HOCO_STARTUP_SPEED_MODE
577
578 /* Set the startup speed of the HOCO when entering snooze mode. */
579 sbycr |= (uint32_t) (p_cfg->lpm_hoco_startup_speed << R_SYSTEM_SBYCR_FWKUP_Pos);
580 #endif
581 #if BSP_FEATURE_LPM_HAS_STANDBY_SOSC_SELECT
582
583 /* Set the SOSC state in snooze mode. */
584 sbycr |= (uint32_t) (p_cfg->lpm_standby_sosc << R_SYSTEM_SBYCR_RTCLPC_Pos);
585 #endif
586 #ifdef R_SYSTEM_SNZCR_SNZE_Msk
587
588 /* Enable/disable DTC operation */
589 snzcr |= (uint32_t) (p_cfg->dtc_state_in_snooze << R_SYSTEM_SNZCR_SNZDTCEN_Pos);
590
591 /* Set the source that can cause an exit from snooze to normal mode */
592 R_ICU->SELSR0_b.SELS = R_ICU_SELSR0_SELS_Msk & p_cfg->snooze_cancel_sources;
593 #endif
594 #if BSP_FEATURE_ICU_SBYEDCR_MASK > 0
595
596 /* Set the source that can cause an exit from snooze to normal mode */
597 sbyedcr0 |= (uint32_t) p_cfg->snooze_cancel_sources & UINT32_MAX;;
598 #endif
599 #if BSP_FEATURE_LPM_SNZREQCR_MASK > 0
600
601 /* Set all sources that can cause an exit from snooze mode to software standby. */
602 R_SYSTEM->SNZEDCR = (uint8_t) p_cfg->snooze_end_sources & UINT8_MAX;
603 #endif
604 #if BSP_FEATURE_LPM_HAS_SNZEDCR1 == 1
605 R_SYSTEM->SNZEDCR1 = (uint8_t) (p_cfg->snooze_end_sources >> 8U) & UINT8_MAX;
606 #endif
607 }
608 #endif
609
610 #if BSP_FEATURE_LPM_HAS_DEEP_SLEEP
611 if (LPM_MODE_DEEP_SLEEP != p_cfg->low_power_mode)
612 #endif
613 {
614 /* Set SBYCR to Standby/Deep Standby. */
615 #if BSP_FEATURE_LPM_HAS_SBYCR_OPE
616 sbycr = ((uint32_t) p_cfg->output_port_enable) << R_SYSTEM_SBYCR_OPE_Pos;
617 #elif BSP_FEATURE_LPM_SBYCR_WRITE1_B14
618 sbycr = R_SYSTEM_SBYCR_OPE_Msk;
619 #endif
620
621 #if BSP_FEATURE_LPM_HAS_SBYCR_SSBY
622 sbycr |= R_SYSTEM_SBYCR_SSBY_Msk;
623 #endif
624
625 #if BSP_FEATURE_LPM_HAS_DPSBYCR_SRKEEP
626
627 /* Configure Standby RAM retention in software standby and deep software standby modes. */
628 dpsbycr |= (uint8_t) (p_cfg->ram_retention_cfg.standby_ram_retention << R_SYSTEM_DPSBYCR_SRKEEP_Pos);
629 #endif
630 }
631
632 if ((LPM_MODE_SLEEP == p_cfg->low_power_mode) || (LPM_MODE_STANDBY_SNOOZE == p_cfg->low_power_mode))
633 {
634 #if BSP_FEATURE_LPM_HAS_FLASH_MODE_SELECT
635
636 /* Flash mode in sleep mode or in snooze mode. */
637 sbycr |= (uint32_t) (p_cfg->lpm_flash_mode_select << R_SYSTEM_SBYCR_FLSTP_Pos);
638 #endif
639 }
640
641 if ((LPM_MODE_DEEP_SLEEP == p_cfg->low_power_mode) || (LPM_MODE_STANDBY == p_cfg->low_power_mode))
642 {
643 #if BSP_FEATURE_LPM_HAS_PDRAMSCR
644
645 /* Configure TCM retention settings in deep sleep or standby mode. */
646 R_SYSTEM->PDRAMSCR1 = p_cfg->ram_retention_cfg.tcm_retention;
647 #endif
648 }
649
650 if (LPM_MODE_STANDBY == p_cfg->low_power_mode)
651 {
652 #if BSP_FEATURE_LPM_HAS_PDRAMSCR
653
654 /* Configure RAM retention settings in standby mode. */
655 R_SYSTEM->PDRAMSCR0 = p_cfg->ram_retention_cfg.ram_retention;
656 #endif
657
658 #if BSP_FEATURE_LPM_HAS_LDO_CONTROL
659
660 /* PLL1LDOCR may only be written in High Speed Mode. If PLL1DOCR setting is not changed, then skip
661 * writing to it. */
662 if (R_SYSTEM->PLL1LDOCR_b.SKEEP != p_cfg->ldo_standby_cfg.pll1_ldo)
663 {
664 R_SYSTEM->PLL1LDOCR_b.SKEEP = (uint8_t) (p_cfg->ldo_standby_cfg.pll1_ldo & 0x01);
665 }
666
667 /* PLL2LDOCR may only be written in High Speed Mode. If PLL2DOCR setting is not changed, then skip
668 * writing to it. */
669 if (R_SYSTEM->PLL2LDOCR_b.SKEEP != p_cfg->ldo_standby_cfg.pll2_ldo)
670 {
671 R_SYSTEM->PLL2LDOCR_b.SKEEP = (uint8_t) (p_cfg->ldo_standby_cfg.pll2_ldo & 0x01);
672 }
673
674 /* HOCOLDOCR may only be written in High Speed Mode. If HOCOLDOCR setting is not changed, then skip
675 * writing to it. */
676 if (R_SYSTEM->HOCOLDOCR_b.SKEEP != p_cfg->ldo_standby_cfg.hoco_ldo)
677 {
678 R_SYSTEM->HOCOLDOCR_b.SKEEP = (uint8_t) (p_cfg->ldo_standby_cfg.hoco_ldo & 0x01);
679 }
680 #endif
681 #if BSP_FEATURE_LPM_HAS_STANDBY_SOSC_SELECT
682
683 /* Set the SOSC state in standby Mode. */
684 sbycr |= (uint32_t) (p_cfg->lpm_standby_sosc << R_SYSTEM_SBYCR_RTCLPC_Pos);
685 #endif
686 }
687
688 #if BSP_FEATURE_ICU_WUPEN_MASK > 0
689 R_ICU->WUPEN = (uint32_t) p_cfg->standby_wake_sources & UINT32_MAX;
690 #endif
691 #if BSP_FEATURE_ICU_HAS_WUPEN1 == 1
692 R_ICU->WUPEN1 = (uint32_t) (p_cfg->standby_wake_sources >> LPM_WUPEN1_OFFSET) & UINT32_MAX;
693 #endif
694 #if BSP_FEATURE_ICU_SBYEDCR_MASK > 0
695 sbyedcr0 |= (uint32_t) p_cfg->standby_wake_sources & UINT32_MAX;
696 sbyedcr1 |= (uint32_t) (p_cfg->standby_wake_sources >> LPM_SBYEDCR1_OFFSET) & UINT32_MAX;
697 #endif
698 }
699 else
700 {
701 /* Set SBYCR to Sleep mode. */
702 #if BSP_FEATURE_LPM_SBYCR_WRITE1_B14
703 sbycr = 1U << R_SYSTEM_SBYCR_OPE_Pos;
704 #elif BSP_FEATURE_LPM_HAS_FLASH_MODE_SELECT
705
706 /* Flash mode in sleep mode or in snooze mode. */
707 sbycr |= (uint32_t) (p_cfg->lpm_flash_mode_select << R_SYSTEM_SBYCR_FLSTP_Pos);
708 #else
709 sbycr = 0;
710 #endif
711 }
712
713 #if BSP_FEATURE_ICU_SBYEDCR_MASK > 0
714 R_ICU->SBYEDCR0 = sbyedcr0;
715 R_ICU->SBYEDCR1 = sbyedcr1;
716 #endif
717 #if BSP_FEATURE_LPM_HAS_SBYCR_SSBY
718 #if LPM_CFG_STANDBY_LIMIT
719 R_SYSTEM->SBYCR = (uint16_t) (sbycr & ~(1U << R_SYSTEM_SBYCR_SSBY_Pos));
720 #else
721 R_SYSTEM->SBYCR = (uint16_t) sbycr;
722 #endif
723 #else
724 R_SYSTEM->SBYCR = (uint8_t) sbycr;
725 #endif
726
727 #if BSP_FEATURE_LPM_HAS_LPSCR
728 #if !LPM_CFG_STANDBY_LIMIT
729 R_SYSTEM->LPSCR = r_lpm_lpscr_calculate(p_cfg);
730 #else
731 R_SYSTEM->LPSCR = 0;
732 #endif
733 #endif
734
735 #ifdef R_SYSTEM_SNZCR_SNZE_Msk
736 R_SYSTEM->SNZCR = (uint8_t) snzcr;
737 #endif
738
739 #if BSP_FEATURE_LPM_HAS_DEEP_STANDBY
740 R_SYSTEM->DPSBYCR = (uint8_t) dpsbycr;
741 #endif
742
743 R_BSP_RegisterProtectEnable(BSP_REG_PROTECT_OM_LPC_BATT);
744
745 return FSP_SUCCESS;
746 }
747
748 #ifdef R_SYSTEM_SNZCR_SNZE_Msk
749
750 /*******************************************************************************************************************//**
751 * Check the clock settings
752 *
753 * @param[in] clock_source The clock source
754 *
755 * @retval FSP_SUCCESS Clock settings are valid.
756 * @retval FSP_ERR_INVALID_MODE One of the following:
757 * - HOCO was not system clock when using snooze mode with SCI0/RXD0.
758 * - HOCO was not stable when using snooze mode with SCI0/RXD0.
759 * - MOCO was running when using snooze mode with SCI0/RXD0.
760 * - MAIN OSCILLATOR was running when using snooze mode with SCI0/RXD0.
761 * - PLL was running when using snooze mode with SCI0/RXD0.
762 * - PLL2 was running when using snooze mode with SCI0/RXD0.
763 **********************************************************************************************************************/
r_lpm_check_clocks(uint32_t clock_source)764 fsp_err_t r_lpm_check_clocks (uint32_t clock_source)
765 {
766 /* Verify the clock source is HOCO */
767 FSP_ERROR_RETURN(LPM_CLOCK_HOCO == clock_source, FSP_ERR_INVALID_MODE);
768
769 /* Verify Moco, Main Osc and PLL are stopped. */
770 FSP_ERROR_RETURN(1U == (*gp_lpm_clock_stp_registers[LPM_CLOCK_MOCO]), FSP_ERR_INVALID_MODE);
771 FSP_ERROR_RETURN(1U == (*gp_lpm_clock_stp_registers[LPM_CLOCK_MAIN_OSC]), FSP_ERR_INVALID_MODE);
772 #if BSP_FEATURE_CGC_HAS_PLL
773 FSP_ERROR_RETURN(1U == (*gp_lpm_clock_stp_registers[LPM_CLOCK_PLL]), FSP_ERR_INVALID_MODE);
774 #endif
775 #if BSP_FEATURE_CGC_HAS_PLL2
776 FSP_ERROR_RETURN(1U == (*gp_lpm_clock_stp_registers[LPM_CLOCK_PLL2]), FSP_ERR_INVALID_MODE);
777 #endif
778
779 return FSP_SUCCESS;
780 }
781
782 #endif
783
784 /*******************************************************************************************************************//**
785 * Perform pre-WFI execution tasks, enter low power mode, Perform post-WFI execution tasks
786 *
787 * @note This function will unlock and lock registers as needed
788 *
789 * @retval FSP_SUCCESS Successfully entered and woke from low power mode.
790 * @retval FSP_ERR_INVALID_MODE One of the following:
791 * - FLL function is enabled when requesting Software Standby.
792 * - HOCO was not system clock when using snooze mode with SCI0/RXD0.
793 * - HOCO was not stable when using snooze mode with SCI0/RXD0.
794 * - MOCO was running when using snooze mode with SCI0/RXD0.
795 * - MAIN OSCILLATOR was running when using snooze mode with SCI0/RXD0.
796 * - PLL was running when using snooze mode with SCI0/RXD0.
797 * - Unable to disable ocillator stop detect when using standby or deep standby.
798 **********************************************************************************************************************/
r_lpm_low_power_enter(lpm_instance_ctrl_t * const p_instance_ctrl)799 fsp_err_t r_lpm_low_power_enter (lpm_instance_ctrl_t * const p_instance_ctrl)
800 {
801 #if BSP_FEATURE_LPM_HAS_DEEP_STANDBY
802 uint32_t saved_opccr = 0U;
803 uint8_t volatile * p_opccr = &R_SYSTEM->OPCCR;
804 #if BSP_FEATURE_CGC_HAS_SOPCCR
805 uint32_t saved_sopccr = 0U;
806 #endif
807 uint32_t saved_ostdcr_ostde = 0U;
808 uint8_t volatile * p_ostde = &R_SYSTEM->OSTDCR;
809 #if BSP_FEATURE_CGC_HOCOWTCR_SCI_SNOOZE_VALUE > 0
810 uint32_t saved_hocowtcr = 0U;
811 uint32_t new_hocowtcr = 0U;
812 #endif
813 #if BSP_FEATURE_BSP_POWER_CHANGE_MSTP_REQUIRED
814 uint32_t stopped_modules = 0;
815 #endif
816 #endif
817
818 #if BSP_PRV_POWER_USE_DCDC
819 bsp_power_mode_t power_mode = BSP_POWER_MODE_LDO;
820 #endif
821
822 #if BSP_TZ_SECURE_BUILD && BSP_FEATURE_TZ_VERSION == 2
823 if (1 == R_SYSTEM->LPMSAR_b.NONSEC0)
824 {
825 /* If security attribution of OPCCR is set to non-secure, then use the non-secure alias. */
826 p_opccr = (uint8_t volatile *) ((uint32_t) p_opccr | BSP_FEATURE_TZ_NS_OFFSET);
827 }
828
829 if (1 == R_SYSTEM->CGFSAR_b.NONSEC06)
830 {
831 /* If security attribution of OSTDCR is set to non-secure, then use the non-secure alias. */
832 p_ostde = (uint8_t volatile *) ((uint32_t) p_ostde | BSP_FEATURE_TZ_NS_OFFSET);
833 }
834 #endif
835 #if BSP_FEATURE_LPM_HAS_SBYCR_SSBY
836 if (1U == R_SYSTEM->SBYCR_b.SSBY)
837 #else
838 if (LPM_LPSCR_SOFTWARE_STANDBY_MODE <= R_SYSTEM->LPSCR)
839 #endif
840 {
841 /* Execute pre-wfi standby tasks */
842
843 #if BSP_PRV_HOCO_USE_FLL
844
845 /* If FLL is available it must not be active when entering Software Standby. */
846 FSP_ERROR_RETURN(0U == R_SYSTEM->FLLCR1, FSP_ERR_INVALID_MODE);
847 #endif
848
849 #if BSP_FEATURE_LPM_HAS_SNOOZE
850
851 /* Get system clock */
852 #if BSP_FEATURE_CGC_STARTUP_SCKSCR
853 uint32_t clock_source = R_SYSTEM->SCKSCR;
854 #endif
855 #endif
856
857 #if !BSP_FEATURE_LPM_HAS_DEEP_STANDBY
858 #ifdef R_SYSTEM_SNZCR_SNZE_Msk
859 if (1U == R_SYSTEM->SNZCR_b.RXDREQEN)
860 {
861 /* Verify clock settings. */
862 FSP_ERROR_RETURN(FSP_SUCCESS == r_lpm_check_clocks(clock_source), FSP_ERR_INVALID_MODE);
863 }
864 #endif
865 #else
866
867 /* Save the OPCCR and SOPCCR registers. When transitioning from Software Standby mode to Normal or Snooze mode
868 * these registers are overwritten. See Section 11.2.6 "Operating Power Control Register" in the RA6M3 manual
869 * R01UM0004EU0110 */
870 saved_opccr = (*p_opccr & R_SYSTEM_OPCCR_OPCM_Msk) >> R_SYSTEM_OPCCR_OPCM_Pos;
871 #if BSP_FEATURE_CGC_HAS_SOPCCR
872 saved_sopccr = R_SYSTEM->SOPCCR_b.SOPCM;
873 #endif
874
875 #if BSP_FEATURE_CGC_HOCOWTCR_SCI_SNOOZE_VALUE > 0
876
877 /* Save HOCOWTCR_b.HSTS */
878 saved_hocowtcr = R_SYSTEM->HOCOWTCR_b.HSTS;
879 #endif
880
881 #if BSP_FEATURE_LPM_HAS_SBYCR_SSBY
882 if (0U == R_SYSTEM->DPSBYCR_b.DPSBY)
883 #else
884 if (LPM_LPSCR_DEEP_SOFTWARE_STANDBY_MODE1 > R_SYSTEM->LPSCR)
885 #endif
886 {
887 #if BSP_FEATURE_LPM_HAS_SNOOZE
888
889 /* Check Snooze configuration settings. Set HOCOWTCR based on current configuration. See Section 11.2.1
890 * "Standby Control Register" in the RA6M3 manual R01UM0004EU0110 */
891 if (1U == R_SYSTEM->SNZCR_b.RXDREQEN)
892 {
893 /* Verify clock settings. */
894 FSP_ERROR_RETURN(FSP_SUCCESS == r_lpm_check_clocks(clock_source), FSP_ERR_INVALID_MODE);
895 #if BSP_FEATURE_CGC_HOCOWTCR_SCI_SNOOZE_VALUE > 0
896 new_hocowtcr = BSP_FEATURE_CGC_HOCOWTCR_SCI_SNOOZE_VALUE;
897 }
898 else
899 {
900 new_hocowtcr = BSP_FEATURE_CGC_HOCOWTCR_VALUE;
901 #endif
902 }
903
904 #else
905 #if BSP_FEATURE_CGC_HAS_HOCOWTCR == 1
906 new_hocowtcr = LPM_SW_STANDBY_HOCOWTCR_HSTS;
907 #endif
908 #endif
909
910 /* Enable writing to CGC register. */
911 R_BSP_RegisterProtectDisable(BSP_REG_PROTECT_CGC);
912
913 #if BSP_FEATURE_LPM_HAS_STCONR == 1
914
915 /* Set STCONR based on the current system clock. */
916 if (LPM_CLOCK_HOCO == clock_source)
917 {
918 #if BSP_FEATURE_CGC_HOCOWTCR_SCI_SNOOZE_VALUE > 0
919
920 /* Set HOCOWTCR_b.HSTS when using HOCO as the system clock */
921 R_SYSTEM->HOCOWTCR_b.HSTS = R_SYSTEM_HOCOWTCR_HSTS_Msk & (new_hocowtcr << R_SYSTEM_HOCOWTCR_HSTS_Pos);
922 #endif
923
924 R_SYSTEM->STCONR = LPM_SW_STANDBY_STCONR;
925 }
926 else
927 {
928 R_SYSTEM->STCONR = LPM_SW_STANDBY_WAKE_STCONR;
929 }
930 #endif
931 }
932 else
933 {
934 /* Enable writing to CGC register. */
935 R_BSP_RegisterProtectDisable(BSP_REG_PROTECT_CGC);
936
937 /* Execute pre-wfi deep standby tasks */
938 /* Clear the DOCDF flag to 0 before entering Deep Software Standby mode. */
939 R_SYSTEM->SYOCDCR_b.DOCDF = 0U;
940
941 /* Clear Deep Software Standby Interrupt Flag Registers. A dummy read is required before writing to DPSIFR.
942 * See Section 11.2.16 "Deep Software Standby Interrupt Flag Register 0" in the
943 * RA6M3 manual R01UM0004EU0110 */
944 R_SYSTEM->DPSIFR0;
945 R_SYSTEM->DPSIFR0 = 0U;
946
947 R_SYSTEM->DPSIFR1;
948 R_SYSTEM->DPSIFR1 = 0U;
949
950 R_SYSTEM->DPSIFR2;
951 R_SYSTEM->DPSIFR2 = 0U;
952
953 R_SYSTEM->DPSIFR3;
954 R_SYSTEM->DPSIFR3 = 0U;
955 }
956
957 /* Save oscillator stop detect state. */
958 saved_ostdcr_ostde = (*p_ostde & R_SYSTEM_OSTDCR_OSTDE_Msk) >> R_SYSTEM_OSTDCR_OSTDE_Pos;
959 *p_ostde &= (uint8_t) ~R_SYSTEM_OSTDCR_OSTDE_Msk;
960
961 #if BSP_FEATURE_BSP_POWER_CHANGE_MSTP_REQUIRED
962 stopped_modules = bsp_prv_power_change_mstp_set();
963
964 /* Delay for >750 ns if any modules changed state */
965 if (0 != stopped_modules)
966 {
967 R_BSP_SoftwareDelay(1U, BSP_DELAY_UNITS_MICROSECONDS);
968 }
969 #endif
970 #endif
971 #if BSP_PRV_POWER_USE_DCDC
972
973 /* DCDC cannot be used in Software Standby, so switch back to LDO if needed (see RA2L1 User's Manual
974 * (R01UH0853EJ0100) Section 40.3 Usage Notes). */
975 if (R_SYSTEM->DCDCCTL & R_SYSTEM_DCDCCTL_DCDCON_Msk)
976 {
977 power_mode = R_BSP_PowerModeSet(BSP_POWER_MODE_LDO_BOOST);
978 }
979 #endif
980 }
981
982 #if BSP_FEATURE_LPM_HAS_SNOOZE
983 if (LPM_MODE_STANDBY_SNOOZE == p_instance_ctrl->p_cfg->low_power_mode)
984 {
985 #ifdef R_SYSTEM_SNZCR_SNZE_Msk
986
987 /* Enable Snooze mode (SNZCR.SNZE = 1) immediately before entering to Software Standby mode.
988 * See Section 11.8.2 "Canceling Snooze Mode" in the RA6M3 manual R01UM0004EU0110 */
989 R_SYSTEM->SNZCR_b.SNZE = 1;
990
991 /* Dummy read required.
992 * infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dai0321a/BIHICBGB.html */
993 R_SYSTEM->SNZCR;
994 #endif
995 }
996 #endif
997
998 #if BSP_FEATURE_LPM_HAS_DEEP_SLEEP
999 if (LPM_MODE_SLEEP != p_instance_ctrl->p_cfg->low_power_mode)
1000 {
1001 /* Set the SLEEPDEEP bit. */
1002 SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
1003 }
1004 #endif
1005
1006 #if BSP_CFG_SLEEP_MODE_DELAY_ENABLE
1007 bool clock_slowed = bsp_prv_clock_prepare_pre_sleep();
1008 #endif
1009
1010 /* DSB should be last instruction executed before WFI
1011 * infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dai0321a/BIHICBGB.html */
1012 __DSB();
1013
1014 __WFI();
1015
1016 #if BSP_CFG_SLEEP_MODE_DELAY_ENABLE
1017 bsp_prv_clock_prepare_post_sleep(clock_slowed);
1018 #endif
1019
1020 #if BSP_FEATURE_LPM_HAS_DEEP_SLEEP
1021 if (LPM_MODE_SLEEP != p_instance_ctrl->p_cfg->low_power_mode)
1022 {
1023 /* Clear the SLEEPDEEP bit. */
1024 SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk;
1025 }
1026 #endif
1027
1028 #ifdef R_SYSTEM_SNZCR_SNZE_Msk
1029
1030 /* Disable Snooze mode (SNZCR.SNZE = 0) immediately after canceling Snooze mode.
1031 * See Section 11.8.2 "Canceling Snooze Mode" in the RA6M3 manual R01UM0004EU0110 */
1032 R_SYSTEM->SNZCR_b.SNZE = 0;
1033 #endif
1034 #if BSP_FEATURE_LPM_HAS_DEEP_STANDBY || (BSP_PRV_POWER_USE_DCDC)
1035 #if BSP_FEATURE_LPM_HAS_SBYCR_SSBY
1036 if (1U == R_SYSTEM->SBYCR_b.SSBY)
1037 #else
1038 if (LPM_LPSCR_SOFTWARE_STANDBY_MODE <= R_SYSTEM->LPSCR)
1039 #endif
1040 {
1041 #if BSP_FEATURE_LPM_HAS_DEEP_STANDBY
1042
1043 /* Wait for ongoing operating mode transition (OPCMTSF, SOPCMTSF) */
1044 r_lpm_wait_for_operating_mode_flags();
1045
1046 /* Restore system registers to the values prior to entering standby. */
1047 *p_opccr = saved_opccr & R_SYSTEM_OPCCR_OPCM_Msk;
1048
1049 #if BSP_FEATURE_CGC_HAS_SOPCCR
1050 R_SYSTEM->SOPCCR = saved_sopccr & R_SYSTEM_SOPCCR_SOPCM_Msk;
1051 #endif
1052
1053 *p_ostde |= (uint8_t) saved_ostdcr_ostde;
1054 #if BSP_FEATURE_CGC_HOCOWTCR_SCI_SNOOZE_VALUE > 0
1055 R_SYSTEM->HOCOWTCR_b.HSTS = R_SYSTEM_HOCOWTCR_HSTS_Msk & (saved_hocowtcr << R_SYSTEM_HOCOWTCR_HSTS_Pos);
1056 #endif
1057
1058 /* Disable writing to CGC register. */
1059 R_BSP_RegisterProtectEnable(BSP_REG_PROTECT_CGC);
1060
1061 #if BSP_FEATURE_BSP_POWER_CHANGE_MSTP_REQUIRED
1062 bsp_prv_power_change_mstp_clear(stopped_modules);
1063 #endif
1064 #endif
1065 #if BSP_PRV_POWER_USE_DCDC
1066 if (power_mode < BSP_POWER_MODE_LDO)
1067 {
1068 /* Switch back to DCDC if it was enabled before. */
1069 R_BSP_PowerModeSet(power_mode);
1070 }
1071 #endif
1072 }
1073 #endif
1074
1075 return FSP_SUCCESS;
1076 }
1077
1078 /*******************************************************************************************************************//**
1079 * Wait for opccr and sopccr transition flags to clear.
1080 **********************************************************************************************************************/
r_lpm_wait_for_operating_mode_flags(void)1081 void r_lpm_wait_for_operating_mode_flags (void)
1082 {
1083 #if BSP_FEATURE_CGC_HAS_OPCCR
1084
1085 /* Wait for transition to complete. */
1086 FSP_HARDWARE_REGISTER_WAIT((FSP_STYPE3_REG8_READ(R_SYSTEM->OPCCR,
1087 !R_SYSTEM->LPMSAR_b.NONSEC0) & R_SYSTEM_OPCCR_OPCMTSF_Msk),
1088 0U);
1089 #endif
1090
1091 #if BSP_FEATURE_CGC_HAS_SOPCCR
1092
1093 /* Wait for transition to complete. */
1094 FSP_HARDWARE_REGISTER_WAIT(R_SYSTEM->SOPCCR_b.SOPCMTSF, 0U);
1095 #endif
1096 }
1097
1098 #if BSP_FEATURE_LPM_HAS_LPSCR
1099
1100 /*******************************************************************************************************************//**
1101 * Calculate the correct value of LPSCR based on the mode.
1102 **********************************************************************************************************************/
r_lpm_lpscr_calculate(lpm_cfg_t const * p_cfg)1103 static uint8_t r_lpm_lpscr_calculate (lpm_cfg_t const * p_cfg)
1104 {
1105 uint8_t lpscr = 0;
1106
1107 switch (p_cfg->low_power_mode)
1108 {
1109 case LPM_MODE_SLEEP:
1110 {
1111 lpscr = LPM_LPSCR_SYSTEM_ACTIVE;
1112 break;
1113 }
1114
1115 case LPM_MODE_DEEP_SLEEP:
1116 {
1117 lpscr = LPM_LPSCR_SYSTEM_ACTIVE;
1118 break;
1119 }
1120
1121 case LPM_MODE_STANDBY:
1122 {
1123 lpscr = LPM_LPSCR_SOFTWARE_STANDBY_MODE;
1124 break;
1125 }
1126
1127 case LPM_MODE_DEEP:
1128 {
1129 lpscr = LPM_LPSCR_DEEP_SOFTWARE_STANDBY_MODE1;
1130 lpscr |= p_cfg->power_supply_state;
1131 break;
1132 }
1133
1134 default:
1135 {
1136 break;
1137 }
1138 }
1139
1140 return lpscr;
1141 }
1142
1143 #endif
1144