nuttx/arch/arm/src/stm32u5/stm32_pwr.c
Xiang Xiao 54e630e14d arch: Merge up_arch.h into up_internal.h
Signed-off-by: Xiang Xiao <xiaoxiang@xiaomi.com>
2022-03-14 09:32:17 +02:00

297 lines
8.1 KiB
C

/****************************************************************************
* arch/arm/src/stm32u5/stm32_pwr.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <nuttx/arch.h>
#include <assert.h>
#include <errno.h>
#include <stdbool.h>
#include <stdint.h>
#include "arm_internal.h"
#include "stm32_pwr.h"
#include "stm32_rcc.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define PWR_TIMEOUT (10 * CONFIG_BOARD_LOOPSPERMSEC)
/****************************************************************************
* Private Functions
****************************************************************************/
static inline uint16_t stm32_pwr_getreg(uint8_t offset)
{
return (uint16_t)getreg32(STM32_PWR_BASE + (uint32_t)offset);
}
static inline void stm32_pwr_putreg(uint8_t offset, uint16_t value)
{
putreg32((uint32_t)value, STM32_PWR_BASE + (uint32_t)offset);
}
static inline void stm32_pwr_modifyreg(uint8_t offset, uint16_t clearbits,
uint16_t setbits)
{
modifyreg32(STM32_PWR_BASE + (uint32_t)offset, (uint32_t)clearbits,
(uint32_t)setbits);
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: enableclk
*
* Description:
* Enable/disable the clock to the power control peripheral. Enabling must
* be done after the APB1 clock is validly configured, and prior to using
* any functionality controlled by the PWR block (i.e. much of anything
* else provided by this module).
*
* Input Parameters:
* enable - True: enable the clock to the Power control (PWR) block.
*
* Returned Value:
* True: the PWR block was previously enabled.
*
****************************************************************************/
bool stm32_pwr_enableclk(bool enable)
{
uint32_t regval;
bool wasenabled;
regval = getreg32(STM32_RCC_AHB3ENR);
wasenabled = ((regval & RCC_AHB3ENR_PWREN) != 0);
/* Power interface clock enable. */
if (wasenabled && !enable)
{
/* Disable power interface clock */
regval &= ~RCC_AHB3ENR_PWREN;
putreg32(regval, STM32_RCC_AHB3ENR);
}
else if (!wasenabled && enable)
{
/* Enable power interface clock */
regval |= RCC_AHB3ENR_PWREN;
putreg32(regval, STM32_RCC_AHB3ENR);
}
return wasenabled;
}
/****************************************************************************
* Name: stm32_pwr_enablebkp
*
* Description:
* Enables access to the backup domain (RTC registers, RTC backup data
* registers and backup SRAM).
*
* Input Parameters:
* writable True: enable ability to write to backup domain registers
*
* Returned Value:
* True: The backup domain was previously writable.
*
****************************************************************************/
bool stm32_pwr_enablebkp(bool writable)
{
uint16_t regval;
bool waswritable;
/* Get the current state of the PWR disable Backup domain register */
regval = stm32_pwr_getreg(STM32_PWR_DBPR_OFFSET);
waswritable = ((regval & PWR_DBPR_DBP) != 0);
/* Enable or disable the ability to write */
if (waswritable && !writable)
{
/* Disable backup domain access */
regval &= ~PWR_DBPR_DBP;
stm32_pwr_putreg(STM32_PWR_DBPR_OFFSET, regval);
}
else if (!waswritable && writable)
{
/* Enable backup domain access */
regval |= PWR_DBPR_DBP;
stm32_pwr_putreg(STM32_PWR_DBPR_OFFSET, regval);
/* Enable does not happen right away */
up_udelay(4);
}
return waswritable;
}
/****************************************************************************
* Name stm32_pwr_adjustvcore
*
* Description:
* Adjusts the voltage used for digital peripherals (V_CORE) before
* raising or after decreasing the system clock frequency. Compare
* [RM0456], section 10.5.4 Dynamic voltage scaling management.
*
* Input Parameters:
* sysclock - The frequency in Hertz the system clock will or has been set
* to.
*
****************************************************************************/
void stm32_pwr_adjustvcore(unsigned sysclock)
{
volatile int timeout;
uint32_t vos_range;
/* Select the applicable V_CORE voltage range depending on the new system
* clock frequency.
*/
DEBUGASSERT(sysclock <= 160000000);
if (sysclock > 110000000)
{
vos_range = PWR_VOSR_VOS_RANGE1 | PWR_VOSR_BOOSTEN;
}
else if (sysclock > 55000000)
{
vos_range = PWR_VOSR_VOS_RANGE2 | PWR_VOSR_BOOSTEN;
}
else if (sysclock > 25000000)
{
vos_range = PWR_VOSR_VOS_RANGE3;
}
else
{
vos_range = PWR_VOSR_VOS_RANGE4;
}
modreg32(vos_range, PWR_VOSR_VOS_MASK | PWR_VOSR_BOOSTEN, STM32_PWR_VOSR);
/* Wait until the new V_CORE voltage range has been applied. */
for (timeout = PWR_TIMEOUT; timeout; timeout--)
{
if (getreg32(STM32_PWR_VOSR) & PWR_VOSR_VOSRDY)
{
break;
}
}
DEBUGASSERT(timeout > 0);
/* Wait until the voltage level for the currently used VOS is ready. */
for (timeout = PWR_TIMEOUT; timeout; timeout--)
{
if (getreg32(STM32_PWR_SVMSR) & PWR_SVMSR_ACTVOSRDY)
{
break;
}
}
DEBUGASSERT(timeout > 0);
#if 0
/* Wait until the embedded power distribution (EPOD) booster has been
* enabled, if applicable.
*/
DEBUGASSERT(timeout > 0);
if (vos_range & PWR_VOSR_BOOSTEN)
{
for (timeout = PWR_TIMEOUT; timeout; timeout--)
{
if (getreg32(STM32_PWR_VOSR) & PWR_VOSR_BOOSTRDY)
{
break;
}
}
}
#endif
DEBUGASSERT(timeout > 0);
}
/****************************************************************************
* Name stm32_pwr_enable_smps
*
* Description:
* Select between the Low-Drop Out (LDO) or Switched Mode Power Suppy
* (SMPS) regulator. Compare [RM0456], section 10.5.1 SMPS and LDO
* embedded regulators.
*
* Input Parameters:
* enable - If true, the SMPS regulator will be enabled, otherwise the LDO,
*
****************************************************************************/
void stm32_pwr_enablesmps(bool enable)
{
volatile int timeout;
uint32_t regsel = enable ? PWR_CR3_REGSEL_SMPS : PWR_CR3_REGSEL_LDO;
/* Select the respective regulator. */
modreg32(regsel, PWR_CR3_REGSEL, STM32_PWR_CR3);
/* Wait until the respective regulator has been activated. */
for (timeout = PWR_TIMEOUT; timeout; timeout--)
{
if (enable)
{
if ((getreg32(STM32_PWR_SVMSR) & PWR_SVMSR_REGS) ==
PWR_SVMSR_REGS_SMPS)
{
break;
}
}
else
{
if ((getreg32(STM32_PWR_SVMSR) & PWR_SVMSR_REGS) ==
PWR_SVMSR_REGS_LDO)
{
break;
}
}
}
DEBUGASSERT(timeout > 0);
}