Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:22:48

0001 /*
0002  * SPDX-License-Identifier: BSD-2-Clause
0003  *
0004  * Copyright (C) 2019 embedded brains GmbH & Co. KG
0005  *
0006  * Redistribution and use in source and binary forms, with or without
0007  * modification, are permitted provided that the following conditions
0008  * are met:
0009  * 1. Redistributions of source code must retain the above copyright
0010  *    notice, this list of conditions and the following disclaimer.
0011  * 2. Redistributions in binary form must reproduce the above copyright
0012  *    notice, this list of conditions and the following disclaimer in the
0013  *    documentation and/or other materials provided with the distribution.
0014  *
0015  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0016  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0017  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0018  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0019  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0020  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0021  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0022  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0023  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0024  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0025  * POSSIBILITY OF SUCH DAMAGE.
0026  */
0027 
0028 #include <bsp/power.h>
0029 #include <bsp/linker-symbols.h>
0030 
0031 #include <libchip/chip.h>
0032 
0033 BSP_FAST_TEXT_SECTION static void
0034 pmc_wait_for_master_clock_ready(volatile Pmc *pmc)
0035 {
0036   while ((pmc->PMC_SR & PMC_SR_MCKRDY) == 0) {
0037     /* Wait */
0038   }
0039 }
0040 
0041 BSP_FAST_TEXT_SECTION static void
0042 pmc_set_master_clock_source(volatile Pmc *pmc, uint32_t mckr)
0043 {
0044   pmc->PMC_MCKR =
0045     (pmc->PMC_MCKR & ~PMC_MCKR_CSS_Msk) | (mckr & PMC_MCKR_CSS_Msk);
0046 }
0047 
0048 BSP_FAST_TEXT_SECTION static void
0049 pmc_set_master_clock_prescaler(volatile Pmc *pmc, uint32_t mckr)
0050 {
0051   pmc->PMC_MCKR =
0052     (pmc->PMC_MCKR & ~PMC_MCKR_PRES_Msk) | (mckr & PMC_MCKR_PRES_Msk);
0053 }
0054 
0055 BSP_FAST_TEXT_SECTION static void
0056 pmc_set_master_clock_division(volatile Pmc *pmc, uint32_t mckr)
0057 {
0058   pmc->PMC_MCKR =
0059     (pmc->PMC_MCKR & ~PMC_MCKR_MDIV_Msk) | (mckr & PMC_MCKR_MDIV_Msk);
0060 }
0061 
0062 BSP_FAST_TEXT_SECTION static void
0063 pmc_wait_for_main_rc_osc(volatile Pmc *pmc)
0064 {
0065   while ((pmc->PMC_SR & PMC_SR_MOSCRCS) == 0) {
0066     /* Wait */
0067   }
0068 }
0069 
0070 BSP_FAST_TEXT_SECTION static void
0071 pmc_wait_for_main_osc_selection(volatile Pmc *pmc)
0072 {
0073   while ((pmc->PMC_SR & PMC_SR_MOSCSELS) == 0) {
0074     /* Wait */
0075   }
0076 }
0077 
0078 BSP_FAST_TEXT_SECTION static void
0079 pmc_use_main_rc_osc_4mhz(volatile Pmc *pmc)
0080 {
0081   uint32_t ckgr_mor;
0082 
0083   ckgr_mor = pmc->CKGR_MOR;
0084   ckgr_mor |= CKGR_MOR_KEY_PASSWD;
0085 
0086   /* Enable main RC oscillator */
0087   ckgr_mor |= CKGR_MOR_MOSCRCEN;
0088   PMC->CKGR_MOR = ckgr_mor;
0089   pmc_wait_for_main_rc_osc(pmc);
0090 
0091   /* Set main RC oscillator frequency to 4MHz */
0092   ckgr_mor &= ~CKGR_MOR_MOSCRCF_Msk;
0093   ckgr_mor |= CKGR_MOR_MOSCRCF_4_MHz;
0094   pmc->CKGR_MOR = ckgr_mor;
0095   pmc_wait_for_main_rc_osc(pmc);
0096 
0097   /* Switch to main RC oscillator */
0098   ckgr_mor &= ~CKGR_MOR_MOSCSEL;
0099   pmc->CKGR_MOR = ckgr_mor;
0100   pmc_wait_for_main_osc_selection(pmc);
0101   pmc_wait_for_master_clock_ready(pmc);
0102 }
0103 
0104 BSP_FAST_TEXT_SECTION static void
0105 pmc_use_main_ext_osc(volatile Pmc *pmc)
0106 {
0107   uint32_t ckgr_mor;
0108 
0109   ckgr_mor = pmc->CKGR_MOR;
0110   ckgr_mor |= CKGR_MOR_KEY_PASSWD;
0111 
0112   /* Enable main external oscillator */
0113   ckgr_mor |= CKGR_MOR_MOSCRCF_12_MHz | CKGR_MOR_MOSCXTEN | CKGR_MOR_MOSCRCEN |
0114     CKGR_MOR_MOSCXTST(DEFAUTL_MAIN_OSC_COUNT);
0115   PMC->CKGR_MOR = ckgr_mor;
0116   pmc_wait_for_main_rc_osc(pmc);
0117   pmc_wait_for_master_clock_ready(pmc);
0118 
0119   /* Switch to main external oscillator */
0120   ckgr_mor |= CKGR_MOR_MOSCSEL;
0121   pmc->CKGR_MOR = ckgr_mor;
0122   pmc_wait_for_main_osc_selection(pmc);
0123   pmc_wait_for_master_clock_ready(pmc);
0124 }
0125 
0126 BSP_FAST_TEXT_SECTION void
0127 atsam_power_handler_wait_mode(
0128   const atsam_power_control *control,
0129   atsam_power_state state
0130 )
0131 {
0132   rtems_interrupt_level level;
0133   volatile Pmc *pmc;
0134   uint32_t mckr;
0135   uint32_t fmr;
0136   uint32_t fsmr;
0137 
0138   (void) control;
0139   pmc = PMC;
0140 
0141   switch (state) {
0142     case ATSAM_POWER_OFF:
0143       rtems_interrupt_disable(level);
0144 
0145       mckr = pmc->PMC_MCKR;
0146 
0147       /* Switch main clock to main RC oscillator (4MHz) */
0148       pmc_use_main_rc_osc_4mhz(pmc);
0149       pmc_set_master_clock_source(pmc, PMC_MCKR_CSS_MAIN_CLK);
0150       pmc_wait_for_master_clock_ready(pmc);
0151       pmc_set_master_clock_prescaler(pmc, PMC_MCKR_PRES_CLK_1);
0152       pmc_wait_for_master_clock_ready(pmc);
0153       pmc_set_master_clock_division(pmc, PMC_MCKR_MDIV_EQ_PCK);
0154       pmc_wait_for_master_clock_ready(pmc);
0155 
0156       /* Set flash wait state to 0 */
0157       fmr = EFC->EEFC_FMR;
0158       EFC->EEFC_FMR = EEFC_FMR_FWS(0);
0159 
0160       /* Enter wait mode */
0161       fsmr = pmc->PMC_FSMR;
0162       pmc->PMC_FSMR = fsmr | PMC_FSMR_LPM;
0163       pmc->CKGR_MOR = CKGR_MOR_KEY_PASSWD | CKGR_MOR_WAITMODE;
0164       pmc_wait_for_master_clock_ready(pmc);
0165       __asm__ volatile ( "wfe" : : : "memory" );
0166       pmc->PMC_FSMR = fsmr;
0167 
0168       /* Restore main clock */
0169       pmc_set_master_clock_prescaler(pmc, mckr);
0170       pmc_wait_for_master_clock_ready(pmc);
0171       pmc_set_master_clock_division(pmc, mckr);
0172       pmc_wait_for_master_clock_ready(pmc);
0173       pmc_set_master_clock_source(pmc, mckr);
0174       pmc_wait_for_master_clock_ready(pmc);
0175       pmc_use_main_ext_osc(pmc);
0176 
0177       /* Restore flash wait state */
0178       EFC->EEFC_FMR = fmr;
0179 
0180       rtems_interrupt_enable(level);
0181       break;
0182     case ATSAM_POWER_INIT:
0183       rtems_interrupt_disable(level);
0184 
0185       pmc->PMC_FSMR = (pmc->PMC_FSMR & ~PMC_FSMR_FLPM_Msk)
0186         | PMC_FSMR_FLPM(PMC_FSMR_FLPM_FLASH_DEEP_POWERDOWN);
0187 
0188       /*  No Cortex-M7 Deep Sleep mode (Backup Mode) */
0189       SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk;
0190 
0191       rtems_interrupt_enable(level);
0192     default:
0193       break;
0194   }
0195 }