Arrow / Mbed OS DAPLink Reset
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers fsl_smc.c Source File

fsl_smc.c

00001 /*
00002  * Copyright (c) 2015, Freescale Semiconductor, Inc.
00003  * Copyright 2016-2017 NXP
00004  * All rights reserved.
00005  *
00006  * SPDX-License-Identifier: BSD-3-Clause
00007  */
00008 
00009 #include "fsl_smc.h"
00010 #include "fsl_common.h"
00011 
00012 /*******************************************************************************
00013  * Definitions
00014  ******************************************************************************/
00015 /* Component ID definition, used by tools. */
00016 #ifndef FSL_COMPONENT_ID
00017 #define FSL_COMPONENT_ID "platform.drivers.smc"
00018 #endif
00019 
00020 typedef void (*smc_stop_ram_func_t)(void);
00021 
00022 /*******************************************************************************
00023  * Prototypes
00024  ******************************************************************************/
00025 static void SMC_EnterStopRamFunc(void);
00026 
00027 /*******************************************************************************
00028  * Variables
00029  ******************************************************************************/
00030 static uint32_t g_savedPrimask;
00031 
00032 /*
00033  * The ram function code is:
00034  *
00035  *  uint32_t i;
00036  *  for (i=0; i<0x8; i++)
00037  *  {
00038  *      __NOP();
00039  *  }
00040  *  __DSB();
00041  *  __WFI();
00042  *  __ISB();
00043  *
00044  * When entring the stop modes, the flash prefetch might be interrupted, thus
00045  * the prefetched code or data might be broken. To make sure the flash is idle
00046  * when entring the stop modes, the code is moved to ram. And delay for a while
00047  * before WFI to make sure previous flash prefetch is finished.
00048  *
00049  * Only need to do like this when code is in flash, if code is in rom or ram,
00050  * this is not necessary.
00051  */
00052 static uint16_t s_stopRamFuncArray[] = {
00053     0x2000,         /* MOVS R0, #0 */
00054     0x2808,         /* CMP R0, #8 */
00055     0xD202,         /* BCS.N */
00056     0xBF00,         /* NOP */
00057     0x1C40,         /* ADDS R0, R0, #1 */
00058     0xE7FA,         /* B.N */
00059     0xF3BF, 0x8F4F, /* DSB */
00060     0xBF30,         /* WFI */
00061     0xF3BF, 0x8F6F, /* ISB */
00062     0x4770,         /* BX LR */
00063 };
00064 
00065 /*******************************************************************************
00066  * Code
00067  ******************************************************************************/
00068 static void SMC_EnterStopRamFunc(void)
00069 {
00070     uint32_t ramFuncEntry = ((uint32_t)(s_stopRamFuncArray)) + 1U;
00071     smc_stop_ram_func_t stopRamFunc = (smc_stop_ram_func_t)ramFuncEntry;
00072     stopRamFunc();
00073 }
00074 
00075 #if (defined(FSL_FEATURE_SMC_HAS_PARAM) && FSL_FEATURE_SMC_HAS_PARAM)
00076 /*!
00077  * brief Gets the SMC parameter.
00078  *
00079  * This function gets the SMC parameter including the enabled power mdoes.
00080  *
00081  * param base SMC peripheral base address.
00082  * param param         Pointer to the SMC param structure.
00083  */
00084 void SMC_GetParam(SMC_Type *base, smc_param_t *param)
00085 {
00086     uint32_t reg = base->PARAM;
00087     param->hsrunEnable  = (bool)(reg & SMC_PARAM_EHSRUN_MASK);
00088     param->llsEnable  = (bool)(reg & SMC_PARAM_ELLS_MASK);
00089     param->lls2Enable  = (bool)(reg & SMC_PARAM_ELLS2_MASK);
00090     param->vlls0Enable  = (bool)(reg & SMC_PARAM_EVLLS0_MASK);
00091 }
00092 #endif /* FSL_FEATURE_SMC_HAS_PARAM */
00093 
00094 /*!
00095  * brief Prepares to enter stop modes.
00096  *
00097  * This function should be called before entering STOP/VLPS/LLS/VLLS modes.
00098  */
00099 void SMC_PreEnterStopModes(void)
00100 {
00101     g_savedPrimask = DisableGlobalIRQ();
00102     __ISB();
00103 }
00104 
00105 /*!
00106  * brief Recovers after wake up from stop modes.
00107  *
00108  * This function should be called after wake up from STOP/VLPS/LLS/VLLS modes.
00109  * It is used with ref SMC_PreEnterStopModes.
00110  */
00111 void SMC_PostExitStopModes(void)
00112 {
00113     EnableGlobalIRQ(g_savedPrimask);
00114     __ISB();
00115 }
00116 
00117 /*!
00118  * brief Prepares to enter wait modes.
00119  *
00120  * This function should be called before entering WAIT/VLPW modes.
00121  */
00122 void SMC_PreEnterWaitModes(void)
00123 {
00124     g_savedPrimask = DisableGlobalIRQ();
00125     __ISB();
00126 }
00127 
00128 /*!
00129  * brief Recovers after wake up from stop modes.
00130  *
00131  * This function should be called after wake up from WAIT/VLPW modes.
00132  * It is used with ref SMC_PreEnterWaitModes.
00133  */
00134 void SMC_PostExitWaitModes(void)
00135 {
00136     EnableGlobalIRQ(g_savedPrimask);
00137     __ISB();
00138 }
00139 
00140 /*!
00141  * brief Configures the system to RUN power mode.
00142  *
00143  * param base SMC peripheral base address.
00144  * return SMC configuration error code.
00145  */
00146 status_t SMC_SetPowerModeRun(SMC_Type *base)
00147 {
00148     uint8_t reg;
00149 
00150     reg = base->PMCTRL;
00151     /* configure Normal RUN mode */
00152     reg &= ~SMC_PMCTRL_RUNM_MASK;
00153     reg |= (kSMC_RunNormal  << SMC_PMCTRL_RUNM_SHIFT);
00154     base->PMCTRL = reg;
00155 
00156     return kStatus_Success;
00157 }
00158 
00159 #if (defined(FSL_FEATURE_SMC_HAS_HIGH_SPEED_RUN_MODE) && FSL_FEATURE_SMC_HAS_HIGH_SPEED_RUN_MODE)
00160 /*!
00161  * brief Configures the system to HSRUN power mode.
00162  *
00163  * param base SMC peripheral base address.
00164  * return SMC configuration error code.
00165  */
00166 status_t SMC_SetPowerModeHsrun(SMC_Type *base)
00167 {
00168     uint8_t reg;
00169 
00170     reg = base->PMCTRL;
00171     /* configure High Speed RUN mode */
00172     reg &= ~SMC_PMCTRL_RUNM_MASK;
00173     reg |= (kSMC_Hsrun  << SMC_PMCTRL_RUNM_SHIFT);
00174     base->PMCTRL = reg;
00175 
00176     return kStatus_Success;
00177 }
00178 #endif /* FSL_FEATURE_SMC_HAS_HIGH_SPEED_RUN_MODE */
00179 
00180 /*!
00181  * brief Configures the system to WAIT power mode.
00182  *
00183  * param base SMC peripheral base address.
00184  * return SMC configuration error code.
00185  */
00186 status_t SMC_SetPowerModeWait(SMC_Type *base)
00187 {
00188     /* configure Normal Wait mode */
00189     SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk;
00190     __DSB();
00191     __WFI();
00192     __ISB();
00193 
00194     return kStatus_Success;
00195 }
00196 
00197 /*!
00198  * brief Configures the system to Stop power mode.
00199  *
00200  * param base SMC peripheral base address.
00201  * param  option Partial Stop mode option.
00202  * return SMC configuration error code.
00203  */
00204 status_t SMC_SetPowerModeStop(SMC_Type *base, smc_partial_stop_option_t option)
00205 {
00206     uint8_t reg;
00207 
00208 #if (defined(FSL_FEATURE_SMC_HAS_PSTOPO) && FSL_FEATURE_SMC_HAS_PSTOPO)
00209     /* configure the Partial Stop mode in Normal Stop mode */
00210     reg = base->STOPCTRL;
00211     reg &= ~SMC_STOPCTRL_PSTOPO_MASK;
00212     reg |= ((uint32_t)option << SMC_STOPCTRL_PSTOPO_SHIFT);
00213     base->STOPCTRL = reg;
00214 #endif
00215 
00216     /* configure Normal Stop mode */
00217     reg = base->PMCTRL;
00218     reg &= ~SMC_PMCTRL_STOPM_MASK;
00219     reg |= (kSMC_StopNormal  << SMC_PMCTRL_STOPM_SHIFT);
00220     base->PMCTRL = reg;
00221 
00222     /* Set the SLEEPDEEP bit to enable deep sleep mode (stop mode) */
00223     SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
00224 
00225     /* read back to make sure the configuration valid before enter stop mode */
00226     (void)base->PMCTRL;
00227     SMC_EnterStopRamFunc();
00228 
00229     /* check whether the power mode enter Stop mode succeed */
00230     if (base->PMCTRL & SMC_PMCTRL_STOPA_MASK)
00231     {
00232         return kStatus_SMC_StopAbort ;
00233     }
00234     else
00235     {
00236         return kStatus_Success;
00237     }
00238 }
00239 
00240 /*!
00241  * brief Configures the system to VLPR power mode.
00242  *
00243  * param base SMC peripheral base address.
00244  * return SMC configuration error code.
00245  */
00246 status_t SMC_SetPowerModeVlpr(SMC_Type *base
00247 #if (defined(FSL_FEATURE_SMC_HAS_LPWUI) && FSL_FEATURE_SMC_HAS_LPWUI)
00248                               ,
00249                               bool wakeupMode
00250 #endif
00251                               )
00252 {
00253     uint8_t reg;
00254 
00255     reg = base->PMCTRL;
00256 #if (defined(FSL_FEATURE_SMC_HAS_LPWUI) && FSL_FEATURE_SMC_HAS_LPWUI)
00257     /* configure whether the system remains in VLP mode on an interrupt */
00258     if (wakeupMode)
00259     {
00260         /* exits to RUN mode on an interrupt */
00261         reg |= SMC_PMCTRL_LPWUI_MASK;
00262     }
00263     else
00264     {
00265         /* remains in VLP mode on an interrupt */
00266         reg &= ~SMC_PMCTRL_LPWUI_MASK;
00267     }
00268 #endif /* FSL_FEATURE_SMC_HAS_LPWUI */
00269 
00270     /* configure VLPR mode */
00271     reg &= ~SMC_PMCTRL_RUNM_MASK;
00272     reg |= (kSMC_RunVlpr  << SMC_PMCTRL_RUNM_SHIFT);
00273     base->PMCTRL = reg;
00274 
00275     return kStatus_Success;
00276 }
00277 
00278 /*!
00279  * brief Configures the system to VLPW power mode.
00280  *
00281  * param base SMC peripheral base address.
00282  * return SMC configuration error code.
00283  */
00284 status_t SMC_SetPowerModeVlpw(SMC_Type *base)
00285 {
00286     /* configure VLPW mode */
00287     /* Set the SLEEPDEEP bit to enable deep sleep mode */
00288     SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk;
00289     __DSB();
00290     __WFI();
00291     __ISB();
00292 
00293     return kStatus_Success;
00294 }
00295 
00296 /*!
00297  * brief Configures the system to VLPS power mode.
00298  *
00299  * param base SMC peripheral base address.
00300  * return SMC configuration error code.
00301  */
00302 status_t SMC_SetPowerModeVlps(SMC_Type *base)
00303 {
00304     uint8_t reg;
00305 
00306     /* configure VLPS mode */
00307     reg = base->PMCTRL;
00308     reg &= ~SMC_PMCTRL_STOPM_MASK;
00309     reg |= (kSMC_StopVlps  << SMC_PMCTRL_STOPM_SHIFT);
00310     base->PMCTRL = reg;
00311 
00312     /* Set the SLEEPDEEP bit to enable deep sleep mode */
00313     SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
00314 
00315     /* read back to make sure the configuration valid before enter stop mode */
00316     (void)base->PMCTRL;
00317     SMC_EnterStopRamFunc();
00318 
00319     /* check whether the power mode enter VLPS mode succeed */
00320     if (base->PMCTRL & SMC_PMCTRL_STOPA_MASK)
00321     {
00322         return kStatus_SMC_StopAbort ;
00323     }
00324     else
00325     {
00326         return kStatus_Success;
00327     }
00328 }
00329 
00330 #if (defined(FSL_FEATURE_SMC_HAS_LOW_LEAKAGE_STOP_MODE) && FSL_FEATURE_SMC_HAS_LOW_LEAKAGE_STOP_MODE)
00331 /*!
00332  * brief Configures the system to LLS power mode.
00333  *
00334  * param base SMC peripheral base address.
00335  * return SMC configuration error code.
00336  */
00337 status_t SMC_SetPowerModeLls(SMC_Type *base
00338 #if ((defined(FSL_FEATURE_SMC_HAS_LLS_SUBMODE) && FSL_FEATURE_SMC_HAS_LLS_SUBMODE) || \
00339      (defined(FSL_FEATURE_SMC_HAS_LPOPO) && FSL_FEATURE_SMC_HAS_LPOPO))
00340                              ,
00341                              const smc_power_mode_lls_config_t *config
00342 #endif
00343                              )
00344 {
00345     uint8_t reg;
00346 
00347     /* configure to LLS mode */
00348     reg = base->PMCTRL;
00349     reg &= ~SMC_PMCTRL_STOPM_MASK;
00350     reg |= (kSMC_StopLls  << SMC_PMCTRL_STOPM_SHIFT);
00351     base->PMCTRL = reg;
00352 
00353 /* configure LLS sub-mode*/
00354 #if (defined(FSL_FEATURE_SMC_HAS_LLS_SUBMODE) && FSL_FEATURE_SMC_HAS_LLS_SUBMODE)
00355     reg = base->STOPCTRL;
00356     reg &= ~SMC_STOPCTRL_LLSM_MASK;
00357     reg |= ((uint32_t)config->subMode << SMC_STOPCTRL_LLSM_SHIFT);
00358     base->STOPCTRL = reg;
00359 #endif /* FSL_FEATURE_SMC_HAS_LLS_SUBMODE */
00360 
00361 #if (defined(FSL_FEATURE_SMC_HAS_LPOPO) && FSL_FEATURE_SMC_HAS_LPOPO)
00362     if (config->enableLpoClock)
00363     {
00364         base->STOPCTRL &= ~SMC_STOPCTRL_LPOPO_MASK;
00365     }
00366     else
00367     {
00368         base->STOPCTRL |= SMC_STOPCTRL_LPOPO_MASK;
00369     }
00370 #endif /* FSL_FEATURE_SMC_HAS_LPOPO */
00371 
00372     /* Set the SLEEPDEEP bit to enable deep sleep mode */
00373     SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
00374 
00375     /* read back to make sure the configuration valid before enter stop mode */
00376     (void)base->PMCTRL;
00377     SMC_EnterStopRamFunc();
00378 
00379     /* check whether the power mode enter LLS mode succeed */
00380     if (base->PMCTRL & SMC_PMCTRL_STOPA_MASK)
00381     {
00382         return kStatus_SMC_StopAbort ;
00383     }
00384     else
00385     {
00386         return kStatus_Success;
00387     }
00388 }
00389 #endif /* FSL_FEATURE_SMC_HAS_LOW_LEAKAGE_STOP_MODE */
00390 
00391 #if (defined(FSL_FEATURE_SMC_HAS_VERY_LOW_LEAKAGE_STOP_MODE) && FSL_FEATURE_SMC_HAS_VERY_LOW_LEAKAGE_STOP_MODE)
00392 /*!
00393  * brief Configures the system to VLLS power mode.
00394  *
00395  * param base SMC peripheral base address.
00396  * param  config The VLLS power mode configuration structure.
00397  * return SMC configuration error code.
00398  */
00399 status_t SMC_SetPowerModeVlls(SMC_Type *base, const smc_power_mode_vlls_config_t *config)
00400 {
00401     uint8_t reg;
00402 
00403 #if (defined(FSL_FEATURE_SMC_HAS_PORPO) && FSL_FEATURE_SMC_HAS_PORPO)
00404 #if (defined(FSL_FEATURE_SMC_USE_VLLSCTRL_REG) && FSL_FEATURE_SMC_USE_VLLSCTRL_REG) ||     \
00405     (defined(FSL_FEATURE_SMC_USE_STOPCTRL_VLLSM) && FSL_FEATURE_SMC_USE_STOPCTRL_VLLSM) || \
00406     (defined(FSL_FEATURE_SMC_HAS_LLS_SUBMODE) && FSL_FEATURE_SMC_HAS_LLS_SUBMODE)
00407     if (config->subMode  == kSMC_StopSub0 )
00408 #endif
00409     {
00410         /* configure whether the Por Detect work in Vlls0 mode */
00411         if (config->enablePorDetectInVlls0 )
00412         {
00413 #if (defined(FSL_FEATURE_SMC_USE_VLLSCTRL_REG) && FSL_FEATURE_SMC_USE_VLLSCTRL_REG)
00414             base->VLLSCTRL &= ~SMC_VLLSCTRL_PORPO_MASK;
00415 #else
00416             base->STOPCTRL &= ~SMC_STOPCTRL_PORPO_MASK;
00417 #endif
00418         }
00419         else
00420         {
00421 #if (defined(FSL_FEATURE_SMC_USE_VLLSCTRL_REG) && FSL_FEATURE_SMC_USE_VLLSCTRL_REG)
00422             base->VLLSCTRL |= SMC_VLLSCTRL_PORPO_MASK;
00423 #else
00424             base->STOPCTRL |= SMC_STOPCTRL_PORPO_MASK;
00425 #endif
00426         }
00427     }
00428 #endif /* FSL_FEATURE_SMC_HAS_PORPO */
00429 
00430 #if (defined(FSL_FEATURE_SMC_HAS_RAM2_POWER_OPTION) && FSL_FEATURE_SMC_HAS_RAM2_POWER_OPTION)
00431     else if (config->subMode  == kSMC_StopSub2 )
00432     {
00433         /* configure whether the Por Detect work in Vlls0 mode */
00434         if (config->enableRam2InVlls2 )
00435         {
00436 #if (defined(FSL_FEATURE_SMC_USE_VLLSCTRL_REG) && FSL_FEATURE_SMC_USE_VLLSCTRL_REG)
00437             base->VLLSCTRL |= SMC_VLLSCTRL_RAM2PO_MASK;
00438 #else
00439             base->STOPCTRL |= SMC_STOPCTRL_RAM2PO_MASK;
00440 #endif
00441         }
00442         else
00443         {
00444 #if (defined(FSL_FEATURE_SMC_USE_VLLSCTRL_REG) && FSL_FEATURE_SMC_USE_VLLSCTRL_REG)
00445             base->VLLSCTRL &= ~SMC_VLLSCTRL_RAM2PO_MASK;
00446 #else
00447             base->STOPCTRL &= ~SMC_STOPCTRL_RAM2PO_MASK;
00448 #endif
00449         }
00450     }
00451     else
00452     {
00453     }
00454 #endif /* FSL_FEATURE_SMC_HAS_RAM2_POWER_OPTION */
00455 
00456     /* configure to VLLS mode */
00457     reg = base->PMCTRL;
00458     reg &= ~SMC_PMCTRL_STOPM_MASK;
00459     reg |= (kSMC_StopVlls  << SMC_PMCTRL_STOPM_SHIFT);
00460     base->PMCTRL = reg;
00461 
00462 /* configure the VLLS sub-mode */
00463 #if (defined(FSL_FEATURE_SMC_USE_VLLSCTRL_REG) && FSL_FEATURE_SMC_USE_VLLSCTRL_REG)
00464     reg = base->VLLSCTRL;
00465     reg &= ~SMC_VLLSCTRL_VLLSM_MASK;
00466     reg |= ((uint32_t)config->subMode  << SMC_VLLSCTRL_VLLSM_SHIFT);
00467     base->VLLSCTRL = reg;
00468 #else
00469 #if (defined(FSL_FEATURE_SMC_HAS_LLS_SUBMODE) && FSL_FEATURE_SMC_HAS_LLS_SUBMODE)
00470     reg = base->STOPCTRL;
00471     reg &= ~SMC_STOPCTRL_LLSM_MASK;
00472     reg |= ((uint32_t)config->subMode  << SMC_STOPCTRL_LLSM_SHIFT);
00473     base->STOPCTRL = reg;
00474 #else
00475     reg = base->STOPCTRL;
00476     reg &= ~SMC_STOPCTRL_VLLSM_MASK;
00477     reg |= ((uint32_t)config->subMode  << SMC_STOPCTRL_VLLSM_SHIFT);
00478     base->STOPCTRL = reg;
00479 #endif /* FSL_FEATURE_SMC_HAS_LLS_SUBMODE */
00480 #endif
00481 
00482 #if (defined(FSL_FEATURE_SMC_HAS_LPOPO) && FSL_FEATURE_SMC_HAS_LPOPO)
00483     if (config->enableLpoClock )
00484     {
00485         base->STOPCTRL &= ~SMC_STOPCTRL_LPOPO_MASK;
00486     }
00487     else
00488     {
00489         base->STOPCTRL |= SMC_STOPCTRL_LPOPO_MASK;
00490     }
00491 #endif /* FSL_FEATURE_SMC_HAS_LPOPO */
00492 
00493     /* Set the SLEEPDEEP bit to enable deep sleep mode */
00494     SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
00495 
00496     /* read back to make sure the configuration valid before enter stop mode */
00497     (void)base->PMCTRL;
00498     SMC_EnterStopRamFunc();
00499 
00500     /* check whether the power mode enter LLS mode succeed */
00501     if (base->PMCTRL & SMC_PMCTRL_STOPA_MASK)
00502     {
00503         return kStatus_SMC_StopAbort ;
00504     }
00505     else
00506     {
00507         return kStatus_Success;
00508     }
00509 }
00510 #endif /* FSL_FEATURE_SMC_HAS_VERY_LOW_LEAKAGE_STOP_MODE */