Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.
 
 
 

518 rindas
15 KiB

  1. /*
  2. * Copyright (c) 2015, Freescale Semiconductor, Inc.
  3. * Copyright 2016-2020 NXP
  4. * All rights reserved.
  5. *
  6. * SPDX-License-Identifier: BSD-3-Clause
  7. */
  8. #include "fsl_smc.h"
  9. #include "fsl_common.h"
  10. /*******************************************************************************
  11. * Definitions
  12. ******************************************************************************/
  13. /* Component ID definition, used by tools. */
  14. #ifndef FSL_COMPONENT_ID
  15. #define FSL_COMPONENT_ID "platform.drivers.smc"
  16. #endif
  17. #if (defined(FSL_FEATURE_SMC_REG_WIDTH) && (FSL_FEATURE_SMC_REG_WIDTH == 32U))
  18. typedef uint32_t smc_reg_t;
  19. #else
  20. typedef uint8_t smc_reg_t;
  21. #endif
  22. typedef void (*smc_stop_ram_func_t)(void);
  23. /*******************************************************************************
  24. * Prototypes
  25. ******************************************************************************/
  26. static void SMC_EnterStopRamFunc(void);
  27. /*******************************************************************************
  28. * Variables
  29. ******************************************************************************/
  30. static uint32_t g_savedPrimask;
  31. /*
  32. * The ram function code is:
  33. *
  34. * uint32_t i;
  35. * for (i=0; i<0x8; i++)
  36. * {
  37. * __NOP();
  38. * }
  39. * __DSB();
  40. * __WFI();
  41. * __ISB();
  42. *
  43. * When entring the stop modes, the flash prefetch might be interrupted, thus
  44. * the prefetched code or data might be broken. To make sure the flash is idle
  45. * when entring the stop modes, the code is moved to ram. And delay for a while
  46. * before WFI to make sure previous flash prefetch is finished.
  47. *
  48. * Only need to do like this when code is in flash, if code is in rom or ram,
  49. * this is not necessary.
  50. */
  51. static uint16_t s_stopRamFuncArray[] = {
  52. 0x2000, /* MOVS R0, #0 */
  53. 0x2808, /* CMP R0, #8 */
  54. 0xD202, /* BCS.N */
  55. 0xBF00, /* NOP */
  56. 0x1C40, /* ADDS R0, R0, #1 */
  57. 0xE7FA, /* B.N */
  58. 0xF3BF, 0x8F4F, /* DSB */
  59. 0xBF30, /* WFI */
  60. 0xF3BF, 0x8F6F, /* ISB */
  61. 0x4770, /* BX LR */
  62. };
  63. /*******************************************************************************
  64. * Code
  65. ******************************************************************************/
  66. static void SMC_EnterStopRamFunc(void)
  67. {
  68. uint32_t ramFuncEntry = ((uint32_t)(s_stopRamFuncArray)) + 1U;
  69. smc_stop_ram_func_t stopRamFunc = (smc_stop_ram_func_t)ramFuncEntry;
  70. stopRamFunc();
  71. }
  72. #if (defined(FSL_FEATURE_SMC_HAS_PARAM) && FSL_FEATURE_SMC_HAS_PARAM)
  73. /*!
  74. * brief Gets the SMC parameter.
  75. *
  76. * This function gets the SMC parameter including the enabled power mdoes.
  77. *
  78. * param base SMC peripheral base address.
  79. * param param Pointer to the SMC param structure.
  80. */
  81. void SMC_GetParam(SMC_Type *base, smc_param_t *param)
  82. {
  83. uint32_t reg = base->PARAM;
  84. param->hsrunEnable = (bool)(reg & SMC_PARAM_EHSRUN_MASK);
  85. param->llsEnable = (bool)(reg & SMC_PARAM_ELLS_MASK);
  86. param->lls2Enable = (bool)(reg & SMC_PARAM_ELLS2_MASK);
  87. param->vlls0Enable = (bool)(reg & SMC_PARAM_EVLLS0_MASK);
  88. }
  89. #endif /* FSL_FEATURE_SMC_HAS_PARAM */
  90. /*!
  91. * brief Prepares to enter stop modes.
  92. *
  93. * This function should be called before entering STOP/VLPS/LLS/VLLS modes.
  94. */
  95. void SMC_PreEnterStopModes(void)
  96. {
  97. g_savedPrimask = DisableGlobalIRQ();
  98. __ISB();
  99. }
  100. /*!
  101. * brief Recovers after wake up from stop modes.
  102. *
  103. * This function should be called after wake up from STOP/VLPS/LLS/VLLS modes.
  104. * It is used with ref SMC_PreEnterStopModes.
  105. */
  106. void SMC_PostExitStopModes(void)
  107. {
  108. EnableGlobalIRQ(g_savedPrimask);
  109. __ISB();
  110. }
  111. /*!
  112. * brief Prepares to enter wait modes.
  113. *
  114. * This function should be called before entering WAIT/VLPW modes.
  115. */
  116. void SMC_PreEnterWaitModes(void)
  117. {
  118. g_savedPrimask = DisableGlobalIRQ();
  119. __ISB();
  120. }
  121. /*!
  122. * brief Recovers after wake up from stop modes.
  123. *
  124. * This function should be called after wake up from WAIT/VLPW modes.
  125. * It is used with ref SMC_PreEnterWaitModes.
  126. */
  127. void SMC_PostExitWaitModes(void)
  128. {
  129. EnableGlobalIRQ(g_savedPrimask);
  130. __ISB();
  131. }
  132. /*!
  133. * brief Configures the system to RUN power mode.
  134. *
  135. * param base SMC peripheral base address.
  136. * return SMC configuration error code.
  137. */
  138. status_t SMC_SetPowerModeRun(SMC_Type *base)
  139. {
  140. smc_reg_t reg;
  141. reg = base->PMCTRL;
  142. /* configure Normal RUN mode */
  143. reg &= ~(smc_reg_t)SMC_PMCTRL_RUNM_MASK;
  144. reg |= ((smc_reg_t)kSMC_RunNormal << SMC_PMCTRL_RUNM_SHIFT);
  145. base->PMCTRL = reg;
  146. return kStatus_Success;
  147. }
  148. #if (defined(FSL_FEATURE_SMC_HAS_HIGH_SPEED_RUN_MODE) && FSL_FEATURE_SMC_HAS_HIGH_SPEED_RUN_MODE)
  149. /*!
  150. * brief Configures the system to HSRUN power mode.
  151. *
  152. * param base SMC peripheral base address.
  153. * return SMC configuration error code.
  154. */
  155. status_t SMC_SetPowerModeHsrun(SMC_Type *base)
  156. {
  157. smc_reg_t reg;
  158. reg = (base->PMCTRL);
  159. /* configure High Speed RUN mode */
  160. reg &= ~(smc_reg_t)SMC_PMCTRL_RUNM_MASK;
  161. reg |= ((smc_reg_t)kSMC_Hsrun << SMC_PMCTRL_RUNM_SHIFT);
  162. base->PMCTRL = reg;
  163. return kStatus_Success;
  164. }
  165. #endif /* FSL_FEATURE_SMC_HAS_HIGH_SPEED_RUN_MODE */
  166. /*!
  167. * brief Configures the system to WAIT power mode.
  168. *
  169. * param base SMC peripheral base address.
  170. * return SMC configuration error code.
  171. */
  172. status_t SMC_SetPowerModeWait(SMC_Type *base)
  173. {
  174. /* configure Normal Wait mode */
  175. SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk;
  176. __DSB();
  177. __WFI();
  178. __ISB();
  179. return kStatus_Success;
  180. }
  181. /*!
  182. * brief Configures the system to Stop power mode.
  183. *
  184. * param base SMC peripheral base address.
  185. * param option Partial Stop mode option.
  186. * return SMC configuration error code.
  187. */
  188. status_t SMC_SetPowerModeStop(SMC_Type *base, smc_partial_stop_option_t option)
  189. {
  190. smc_reg_t reg;
  191. #if (defined(FSL_FEATURE_SMC_HAS_PSTOPO) && FSL_FEATURE_SMC_HAS_PSTOPO)
  192. /* configure the Partial Stop mode in Normal Stop mode */
  193. reg = base->STOPCTRL;
  194. reg &= ~(smc_reg_t)SMC_STOPCTRL_PSTOPO_MASK;
  195. reg |= ((smc_reg_t)option << SMC_STOPCTRL_PSTOPO_SHIFT);
  196. base->STOPCTRL = reg;
  197. #endif
  198. /* configure Normal Stop mode */
  199. reg = base->PMCTRL;
  200. reg &= ~(smc_reg_t)SMC_PMCTRL_STOPM_MASK;
  201. reg |= ((smc_reg_t)kSMC_StopNormal << SMC_PMCTRL_STOPM_SHIFT);
  202. base->PMCTRL = reg;
  203. /* Set the SLEEPDEEP bit to enable deep sleep mode (stop mode) */
  204. SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
  205. /* read back to make sure the configuration valid before enter stop mode */
  206. (void)base->PMCTRL;
  207. SMC_EnterStopRamFunc();
  208. /* check whether the power mode enter Stop mode succeed */
  209. if (0U != (base->PMCTRL & SMC_PMCTRL_STOPA_MASK))
  210. {
  211. return kStatus_SMC_StopAbort;
  212. }
  213. else
  214. {
  215. return kStatus_Success;
  216. }
  217. }
  218. /*!
  219. * brief Configures the system to VLPR power mode.
  220. *
  221. * param base SMC peripheral base address.
  222. * return SMC configuration error code.
  223. */
  224. status_t SMC_SetPowerModeVlpr(SMC_Type *base
  225. #if (defined(FSL_FEATURE_SMC_HAS_LPWUI) && FSL_FEATURE_SMC_HAS_LPWUI)
  226. ,
  227. bool wakeupMode
  228. #endif
  229. )
  230. {
  231. smc_reg_t reg;
  232. reg = (smc_reg_t)(base->PMCTRL);
  233. #if (defined(FSL_FEATURE_SMC_HAS_LPWUI) && FSL_FEATURE_SMC_HAS_LPWUI)
  234. /* configure whether the system remains in VLP mode on an interrupt */
  235. if (wakeupMode)
  236. {
  237. /* exits to RUN mode on an interrupt */
  238. reg |= SMC_PMCTRL_LPWUI_MASK;
  239. }
  240. else
  241. {
  242. /* remains in VLP mode on an interrupt */
  243. reg &= ~(smc_reg_t)SMC_PMCTRL_LPWUI_MASK;
  244. }
  245. #endif /* FSL_FEATURE_SMC_HAS_LPWUI */
  246. /* configure VLPR mode */
  247. reg &= ~(smc_reg_t)SMC_PMCTRL_RUNM_MASK;
  248. reg |= ((smc_reg_t)kSMC_RunVlpr << SMC_PMCTRL_RUNM_SHIFT);
  249. base->PMCTRL = reg;
  250. return kStatus_Success;
  251. }
  252. /*!
  253. * brief Configures the system to VLPW power mode.
  254. *
  255. * param base SMC peripheral base address.
  256. * return SMC configuration error code.
  257. */
  258. status_t SMC_SetPowerModeVlpw(SMC_Type *base)
  259. {
  260. /* configure VLPW mode */
  261. /* Set the SLEEPDEEP bit to enable deep sleep mode */
  262. SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk;
  263. __DSB();
  264. __WFI();
  265. __ISB();
  266. return kStatus_Success;
  267. }
  268. /*!
  269. * brief Configures the system to VLPS power mode.
  270. *
  271. * param base SMC peripheral base address.
  272. * return SMC configuration error code.
  273. */
  274. status_t SMC_SetPowerModeVlps(SMC_Type *base)
  275. {
  276. smc_reg_t reg;
  277. /* configure VLPS mode */
  278. reg = base->PMCTRL;
  279. reg &= ~(smc_reg_t)SMC_PMCTRL_STOPM_MASK;
  280. reg |= ((smc_reg_t)kSMC_StopVlps << SMC_PMCTRL_STOPM_SHIFT);
  281. base->PMCTRL = reg;
  282. /* Set the SLEEPDEEP bit to enable deep sleep mode */
  283. SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
  284. /* read back to make sure the configuration valid before enter stop mode */
  285. (void)base->PMCTRL;
  286. SMC_EnterStopRamFunc();
  287. /* check whether the power mode enter VLPS mode succeed */
  288. if (0U != (base->PMCTRL & SMC_PMCTRL_STOPA_MASK))
  289. {
  290. return kStatus_SMC_StopAbort;
  291. }
  292. else
  293. {
  294. return kStatus_Success;
  295. }
  296. }
  297. #if (defined(FSL_FEATURE_SMC_HAS_LOW_LEAKAGE_STOP_MODE) && FSL_FEATURE_SMC_HAS_LOW_LEAKAGE_STOP_MODE)
  298. /*!
  299. * brief Configures the system to LLS power mode.
  300. *
  301. * param base SMC peripheral base address.
  302. * return SMC configuration error code.
  303. */
  304. status_t SMC_SetPowerModeLls(SMC_Type *base
  305. #if ((defined(FSL_FEATURE_SMC_HAS_LLS_SUBMODE) && FSL_FEATURE_SMC_HAS_LLS_SUBMODE) || \
  306. (defined(FSL_FEATURE_SMC_HAS_LPOPO) && FSL_FEATURE_SMC_HAS_LPOPO))
  307. ,
  308. const smc_power_mode_lls_config_t *config
  309. #endif
  310. )
  311. {
  312. smc_reg_t reg;
  313. /* configure to LLS mode */
  314. reg = base->PMCTRL;
  315. reg &= ~(smc_reg_t)SMC_PMCTRL_STOPM_MASK;
  316. reg |= ((smc_reg_t)kSMC_StopLls << SMC_PMCTRL_STOPM_SHIFT);
  317. base->PMCTRL = reg;
  318. /* configure LLS sub-mode*/
  319. #if (defined(FSL_FEATURE_SMC_HAS_LLS_SUBMODE) && FSL_FEATURE_SMC_HAS_LLS_SUBMODE)
  320. reg = base->STOPCTRL;
  321. reg &= ~(smc_reg_t)SMC_STOPCTRL_LLSM_MASK;
  322. reg |= ((smc_reg_t)config->subMode << SMC_STOPCTRL_LLSM_SHIFT);
  323. base->STOPCTRL = reg;
  324. #endif /* FSL_FEATURE_SMC_HAS_LLS_SUBMODE */
  325. #if (defined(FSL_FEATURE_SMC_HAS_LPOPO) && FSL_FEATURE_SMC_HAS_LPOPO)
  326. if (config->enableLpoClock)
  327. {
  328. base->STOPCTRL &= ~(smc_reg_t)SMC_STOPCTRL_LPOPO_MASK;
  329. }
  330. else
  331. {
  332. base->STOPCTRL |= (smc_reg_t)SMC_STOPCTRL_LPOPO_MASK;
  333. }
  334. #endif /* FSL_FEATURE_SMC_HAS_LPOPO */
  335. /* Set the SLEEPDEEP bit to enable deep sleep mode */
  336. SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
  337. /* read back to make sure the configuration valid before enter stop mode */
  338. (void)base->PMCTRL;
  339. SMC_EnterStopRamFunc();
  340. /* check whether the power mode enter LLS mode succeed */
  341. if (0U != (base->PMCTRL & SMC_PMCTRL_STOPA_MASK))
  342. {
  343. return kStatus_SMC_StopAbort;
  344. }
  345. else
  346. {
  347. return kStatus_Success;
  348. }
  349. }
  350. #endif /* FSL_FEATURE_SMC_HAS_LOW_LEAKAGE_STOP_MODE */
  351. #if (defined(FSL_FEATURE_SMC_HAS_VERY_LOW_LEAKAGE_STOP_MODE) && FSL_FEATURE_SMC_HAS_VERY_LOW_LEAKAGE_STOP_MODE)
  352. /*!
  353. * brief Configures the system to VLLS power mode.
  354. *
  355. * param base SMC peripheral base address.
  356. * param config The VLLS power mode configuration structure.
  357. * return SMC configuration error code.
  358. */
  359. status_t SMC_SetPowerModeVlls(SMC_Type *base, const smc_power_mode_vlls_config_t *config)
  360. {
  361. smc_reg_t reg;
  362. #if (defined(FSL_FEATURE_SMC_HAS_PORPO) && FSL_FEATURE_SMC_HAS_PORPO)
  363. #if (defined(FSL_FEATURE_SMC_USE_VLLSCTRL_REG) && FSL_FEATURE_SMC_USE_VLLSCTRL_REG) || \
  364. (defined(FSL_FEATURE_SMC_USE_STOPCTRL_VLLSM) && FSL_FEATURE_SMC_USE_STOPCTRL_VLLSM) || \
  365. (defined(FSL_FEATURE_SMC_HAS_LLS_SUBMODE) && FSL_FEATURE_SMC_HAS_LLS_SUBMODE)
  366. if (config->subMode == kSMC_StopSub0)
  367. #endif
  368. {
  369. /* configure whether the Por Detect work in Vlls0 mode */
  370. if (true == config->enablePorDetectInVlls0)
  371. {
  372. #if (defined(FSL_FEATURE_SMC_USE_VLLSCTRL_REG) && FSL_FEATURE_SMC_USE_VLLSCTRL_REG)
  373. base->VLLSCTRL &= ~(smc_reg_t)SMC_VLLSCTRL_PORPO_MASK;
  374. #else
  375. base->STOPCTRL &= ~(smc_reg_t)SMC_STOPCTRL_PORPO_MASK;
  376. #endif
  377. }
  378. else
  379. {
  380. #if (defined(FSL_FEATURE_SMC_USE_VLLSCTRL_REG) && FSL_FEATURE_SMC_USE_VLLSCTRL_REG)
  381. base->VLLSCTRL |= SMC_VLLSCTRL_PORPO_MASK;
  382. #else
  383. base->STOPCTRL |= SMC_STOPCTRL_PORPO_MASK;
  384. #endif
  385. }
  386. }
  387. #endif /* FSL_FEATURE_SMC_HAS_PORPO */
  388. #if (defined(FSL_FEATURE_SMC_HAS_RAM2_POWER_OPTION) && FSL_FEATURE_SMC_HAS_RAM2_POWER_OPTION)
  389. else if (config->subMode == kSMC_StopSub2)
  390. {
  391. /* configure whether the Por Detect work in Vlls0 mode */
  392. if (true == config->enableRam2InVlls2)
  393. {
  394. #if (defined(FSL_FEATURE_SMC_USE_VLLSCTRL_REG) && FSL_FEATURE_SMC_USE_VLLSCTRL_REG)
  395. base->VLLSCTRL |= SMC_VLLSCTRL_RAM2PO_MASK;
  396. #else
  397. base->STOPCTRL |= SMC_STOPCTRL_RAM2PO_MASK;
  398. #endif
  399. }
  400. else
  401. {
  402. #if (defined(FSL_FEATURE_SMC_USE_VLLSCTRL_REG) && FSL_FEATURE_SMC_USE_VLLSCTRL_REG)
  403. base->VLLSCTRL &= ~SMC_VLLSCTRL_RAM2PO_MASK;
  404. #else
  405. base->STOPCTRL &= ~(smc_reg_t)SMC_STOPCTRL_RAM2PO_MASK;
  406. #endif
  407. }
  408. }
  409. else
  410. {
  411. /* Add this to fix MISRA C2012 rule15.7 issue: Empty else without comment. */
  412. }
  413. #endif /* FSL_FEATURE_SMC_HAS_RAM2_POWER_OPTION */
  414. /* configure to VLLS mode */
  415. reg = base->PMCTRL;
  416. reg &= ~(smc_reg_t)SMC_PMCTRL_STOPM_MASK;
  417. reg |= ((smc_reg_t)kSMC_StopVlls << SMC_PMCTRL_STOPM_SHIFT);
  418. base->PMCTRL = reg;
  419. /* configure the VLLS sub-mode */
  420. #if (defined(FSL_FEATURE_SMC_USE_VLLSCTRL_REG) && FSL_FEATURE_SMC_USE_VLLSCTRL_REG)
  421. reg = base->VLLSCTRL;
  422. reg &= ~(smc_reg_t)SMC_VLLSCTRL_VLLSM_MASK;
  423. reg |= ((smc_reg_t)config->subMode << SMC_VLLSCTRL_VLLSM_SHIFT);
  424. base->VLLSCTRL = reg;
  425. #else
  426. #if (defined(FSL_FEATURE_SMC_HAS_LLS_SUBMODE) && FSL_FEATURE_SMC_HAS_LLS_SUBMODE)
  427. reg = base->STOPCTRL;
  428. reg &= ~(smc_reg_t)SMC_STOPCTRL_LLSM_MASK;
  429. reg |= ((smc_reg_t)config->subMode << SMC_STOPCTRL_LLSM_SHIFT);
  430. base->STOPCTRL = reg;
  431. #else
  432. reg = base->STOPCTRL;
  433. reg &= ~(smc_reg_t)SMC_STOPCTRL_VLLSM_MASK;
  434. reg |= ((smc_reg_t)config->subMode << SMC_STOPCTRL_VLLSM_SHIFT);
  435. base->STOPCTRL = reg;
  436. #endif /* FSL_FEATURE_SMC_HAS_LLS_SUBMODE */
  437. #endif
  438. #if (defined(FSL_FEATURE_SMC_HAS_LPOPO) && FSL_FEATURE_SMC_HAS_LPOPO)
  439. if (config->enableLpoClock)
  440. {
  441. base->STOPCTRL &= ~(smc_reg_t)SMC_STOPCTRL_LPOPO_MASK;
  442. }
  443. else
  444. {
  445. base->STOPCTRL |= SMC_STOPCTRL_LPOPO_MASK;
  446. }
  447. #endif /* FSL_FEATURE_SMC_HAS_LPOPO */
  448. /* Set the SLEEPDEEP bit to enable deep sleep mode */
  449. SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
  450. /* read back to make sure the configuration valid before enter stop mode */
  451. (void)base->PMCTRL;
  452. SMC_EnterStopRamFunc();
  453. /* check whether the power mode enter LLS mode succeed */
  454. if (0U != (base->PMCTRL & SMC_PMCTRL_STOPA_MASK))
  455. {
  456. return kStatus_SMC_StopAbort;
  457. }
  458. else
  459. {
  460. return kStatus_Success;
  461. }
  462. }
  463. #endif /* FSL_FEATURE_SMC_HAS_VERY_LOW_LEAKAGE_STOP_MODE */