mirror of
https://gitlab.rtems.org/rtems/rtos/rtems.git
synced 2025-12-26 06:08:20 +00:00
The RTEMS Software Engineering Guide specifies that the SPDX license annotation shouldbe the first line of the file and not part of the copyright/license comment block.
196 lines
5.7 KiB
C
196 lines
5.7 KiB
C
/* SPDX-License-Identifier: BSD-2-Clause */
|
|
|
|
/*
|
|
* Copyright (C) 2019 embedded brains GmbH & Co. KG
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include <bsp/power.h>
|
|
#include <bsp/linker-symbols.h>
|
|
|
|
#include <libchip/chip.h>
|
|
|
|
BSP_FAST_TEXT_SECTION static void
|
|
pmc_wait_for_master_clock_ready(volatile Pmc *pmc)
|
|
{
|
|
while ((pmc->PMC_SR & PMC_SR_MCKRDY) == 0) {
|
|
/* Wait */
|
|
}
|
|
}
|
|
|
|
BSP_FAST_TEXT_SECTION static void
|
|
pmc_set_master_clock_source(volatile Pmc *pmc, uint32_t mckr)
|
|
{
|
|
pmc->PMC_MCKR =
|
|
(pmc->PMC_MCKR & ~PMC_MCKR_CSS_Msk) | (mckr & PMC_MCKR_CSS_Msk);
|
|
}
|
|
|
|
BSP_FAST_TEXT_SECTION static void
|
|
pmc_set_master_clock_prescaler(volatile Pmc *pmc, uint32_t mckr)
|
|
{
|
|
pmc->PMC_MCKR =
|
|
(pmc->PMC_MCKR & ~PMC_MCKR_PRES_Msk) | (mckr & PMC_MCKR_PRES_Msk);
|
|
}
|
|
|
|
BSP_FAST_TEXT_SECTION static void
|
|
pmc_set_master_clock_division(volatile Pmc *pmc, uint32_t mckr)
|
|
{
|
|
pmc->PMC_MCKR =
|
|
(pmc->PMC_MCKR & ~PMC_MCKR_MDIV_Msk) | (mckr & PMC_MCKR_MDIV_Msk);
|
|
}
|
|
|
|
BSP_FAST_TEXT_SECTION static void
|
|
pmc_wait_for_main_rc_osc(volatile Pmc *pmc)
|
|
{
|
|
while ((pmc->PMC_SR & PMC_SR_MOSCRCS) == 0) {
|
|
/* Wait */
|
|
}
|
|
}
|
|
|
|
BSP_FAST_TEXT_SECTION static void
|
|
pmc_wait_for_main_osc_selection(volatile Pmc *pmc)
|
|
{
|
|
while ((pmc->PMC_SR & PMC_SR_MOSCSELS) == 0) {
|
|
/* Wait */
|
|
}
|
|
}
|
|
|
|
BSP_FAST_TEXT_SECTION static void
|
|
pmc_use_main_rc_osc_4mhz(volatile Pmc *pmc)
|
|
{
|
|
uint32_t ckgr_mor;
|
|
|
|
ckgr_mor = pmc->CKGR_MOR;
|
|
ckgr_mor |= CKGR_MOR_KEY_PASSWD;
|
|
|
|
/* Enable main RC oscillator */
|
|
ckgr_mor |= CKGR_MOR_MOSCRCEN;
|
|
PMC->CKGR_MOR = ckgr_mor;
|
|
pmc_wait_for_main_rc_osc(pmc);
|
|
|
|
/* Set main RC oscillator frequency to 4MHz */
|
|
ckgr_mor &= ~CKGR_MOR_MOSCRCF_Msk;
|
|
ckgr_mor |= CKGR_MOR_MOSCRCF_4_MHz;
|
|
pmc->CKGR_MOR = ckgr_mor;
|
|
pmc_wait_for_main_rc_osc(pmc);
|
|
|
|
/* Switch to main RC oscillator */
|
|
ckgr_mor &= ~CKGR_MOR_MOSCSEL;
|
|
pmc->CKGR_MOR = ckgr_mor;
|
|
pmc_wait_for_main_osc_selection(pmc);
|
|
pmc_wait_for_master_clock_ready(pmc);
|
|
}
|
|
|
|
BSP_FAST_TEXT_SECTION static void
|
|
pmc_use_main_ext_osc(volatile Pmc *pmc)
|
|
{
|
|
uint32_t ckgr_mor;
|
|
|
|
ckgr_mor = pmc->CKGR_MOR;
|
|
ckgr_mor |= CKGR_MOR_KEY_PASSWD;
|
|
|
|
/* Enable main external oscillator */
|
|
ckgr_mor |= CKGR_MOR_MOSCRCF_12_MHz | CKGR_MOR_MOSCXTEN | CKGR_MOR_MOSCRCEN |
|
|
CKGR_MOR_MOSCXTST(DEFAUTL_MAIN_OSC_COUNT);
|
|
PMC->CKGR_MOR = ckgr_mor;
|
|
pmc_wait_for_main_rc_osc(pmc);
|
|
pmc_wait_for_master_clock_ready(pmc);
|
|
|
|
/* Switch to main external oscillator */
|
|
ckgr_mor |= CKGR_MOR_MOSCSEL;
|
|
pmc->CKGR_MOR = ckgr_mor;
|
|
pmc_wait_for_main_osc_selection(pmc);
|
|
pmc_wait_for_master_clock_ready(pmc);
|
|
}
|
|
|
|
BSP_FAST_TEXT_SECTION void
|
|
atsam_power_handler_wait_mode(
|
|
const atsam_power_control *control,
|
|
atsam_power_state state
|
|
)
|
|
{
|
|
rtems_interrupt_level level;
|
|
volatile Pmc *pmc;
|
|
uint32_t mckr;
|
|
uint32_t fmr;
|
|
uint32_t fsmr;
|
|
|
|
(void) control;
|
|
pmc = PMC;
|
|
|
|
switch (state) {
|
|
case ATSAM_POWER_OFF:
|
|
rtems_interrupt_disable(level);
|
|
|
|
mckr = pmc->PMC_MCKR;
|
|
|
|
/* Switch main clock to main RC oscillator (4MHz) */
|
|
pmc_use_main_rc_osc_4mhz(pmc);
|
|
pmc_set_master_clock_source(pmc, PMC_MCKR_CSS_MAIN_CLK);
|
|
pmc_wait_for_master_clock_ready(pmc);
|
|
pmc_set_master_clock_prescaler(pmc, PMC_MCKR_PRES_CLK_1);
|
|
pmc_wait_for_master_clock_ready(pmc);
|
|
pmc_set_master_clock_division(pmc, PMC_MCKR_MDIV_EQ_PCK);
|
|
pmc_wait_for_master_clock_ready(pmc);
|
|
|
|
/* Set flash wait state to 0 */
|
|
fmr = EFC->EEFC_FMR;
|
|
EFC->EEFC_FMR = EEFC_FMR_FWS(0);
|
|
|
|
/* Enter wait mode */
|
|
fsmr = pmc->PMC_FSMR;
|
|
pmc->PMC_FSMR = fsmr | PMC_FSMR_LPM;
|
|
pmc->CKGR_MOR = CKGR_MOR_KEY_PASSWD | CKGR_MOR_WAITMODE;
|
|
pmc_wait_for_master_clock_ready(pmc);
|
|
__asm__ volatile ( "wfe" : : : "memory" );
|
|
pmc->PMC_FSMR = fsmr;
|
|
|
|
/* Restore main clock */
|
|
pmc_set_master_clock_prescaler(pmc, mckr);
|
|
pmc_wait_for_master_clock_ready(pmc);
|
|
pmc_set_master_clock_division(pmc, mckr);
|
|
pmc_wait_for_master_clock_ready(pmc);
|
|
pmc_set_master_clock_source(pmc, mckr);
|
|
pmc_wait_for_master_clock_ready(pmc);
|
|
pmc_use_main_ext_osc(pmc);
|
|
|
|
/* Restore flash wait state */
|
|
EFC->EEFC_FMR = fmr;
|
|
|
|
rtems_interrupt_enable(level);
|
|
break;
|
|
case ATSAM_POWER_INIT:
|
|
rtems_interrupt_disable(level);
|
|
|
|
pmc->PMC_FSMR = (pmc->PMC_FSMR & ~PMC_FSMR_FLPM_Msk)
|
|
| PMC_FSMR_FLPM(PMC_FSMR_FLPM_FLASH_DEEP_POWERDOWN);
|
|
|
|
/* No Cortex-M7 Deep Sleep mode (Backup Mode) */
|
|
SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk;
|
|
|
|
rtems_interrupt_enable(level);
|
|
default:
|
|
break;
|
|
}
|
|
}
|