Files
base/drivers/source/smc/sdrv_smc.c
2025-11-07 09:57:14 +08:00

1761 lines
50 KiB
C

/**
* @file sdrv_smc.c
* @brief Sdrv SMC driver source.
*
* @copyright Copyright (c) 2022 Semidrive Semiconductor.
* All rights reserved.
*/
#include <reg.h>
#include <regs_base.h>
#include <param.h>
#include <sdrv_smc.h>
#include "sdrv_smc_reg.h"
#define GET_COM_IRQ_MASK_BASE(m, n) (COM_IRQ_MASK_##m##_OFF(n))
static sdrv_smc_t g_default_smc_ctrl = {
.base = APB_SMC_BASE,
};
static inline uint32_t sdrv_smc_readl(uint32_t base, uint32_t offset)
{
return readl(base + offset);
}
static inline void sdrv_smc_writel(uint32_t base, uint32_t offset, uint32_t value)
{
writel(value, base + offset);
}
static inline uint32_t sdrv_smc_lp_ctl_addr(sdrv_smc_power_switch_e ps)
{
#if CONFIG_E3 || CONFIG_D3
return (ps < SDRV_SMC_POWER_SWITCH_AP_DISP) ? SAF_LP_CTL_OFF(ps) : AP_LP_CTL_OFF(0);
#endif
#if CONFIG_E3L || CONFIG_D3L
return SAF_LP_CTL_OFF(ps);
#endif
}
static inline uint32_t sdrv_smc_lp_ctl_dly_addr(sdrv_smc_power_switch_e ps)
{
#if CONFIG_E3 || CONFIG_D3
return (ps < SDRV_SMC_POWER_SWITCH_AP_DISP) ? SAF_LP_DLY_CTL_OFF(ps) : AP_LP_DLY_CTL_OFF(0);
#endif
#if CONFIG_E3L || CONFIG_D3L
return SAF_LP_DLY_CTL_OFF(ps);
#endif
}
static inline uint32_t sdrv_smc_ram_lp_ctl_addr(sdrv_smc_ram_e ram)
{
#if CONFIG_E3 || CONFIG_D3
return (ram < SDRV_SMC_RAM_AP) ? SAF_RAM_LP_CTL_OFF(ram) : AP_RAM_LP_CTL_OFF((ram - SDRV_SMC_RAM_AP));
#endif
#if CONFIG_E3L || CONFIG_D3L
return SAF_RAM_LP_CTL_OFF(ram);
#endif
}
static void sdrv_smc_core_irq_mask(uint32_t base, sdrv_smc_core_e core, uint16_t mask)
{
uint32_t v = sdrv_smc_readl(base, CORE_IRQ_MASK_OFF(core));
v |= mask;
sdrv_smc_writel(base, CORE_IRQ_MASK_OFF(core), v);
}
static void sdrv_smc_core_irq_unmask(uint32_t base, sdrv_smc_core_e core, uint16_t unmask)
{
uint32_t v = sdrv_smc_readl(base, CORE_IRQ_MASK_OFF(core));
v &= ~unmask;
sdrv_smc_writel(base, CORE_IRQ_MASK_OFF(core), v);
}
static uint32_t sdrv_smc_get_common_irq_mask_offset(sdrv_smc_core_e core,
uint32_t group)
{
uint32_t offset;
switch (group) {
case 0:
offset = GET_COM_IRQ_MASK_BASE(0, core);
break;
case 1:
offset = GET_COM_IRQ_MASK_BASE(1, core);
break;
case 2:
offset = GET_COM_IRQ_MASK_BASE(2, core);
break;
case 3:
offset = GET_COM_IRQ_MASK_BASE(3, core);
break;
case 4:
offset = GET_COM_IRQ_MASK_BASE(4, core);
break;
case 5:
offset = GET_COM_IRQ_MASK_BASE(5, core);
break;
case 6:
offset = GET_COM_IRQ_MASK_BASE(6, core);
break;
case 7:
offset = GET_COM_IRQ_MASK_BASE(7, core);
break;
default:
offset = 0;
break;
}
return offset;
}
static void sdrv_smc_common_irq_mask(uint32_t base, sdrv_smc_core_e core, uint32_t group,
uint32_t mask)
{
uint32_t v, offset;
offset = sdrv_smc_get_common_irq_mask_offset(core, group);
v = sdrv_smc_readl(base, offset);
v |= mask;
sdrv_smc_writel(base, offset, v);
}
static void sdrv_smc_common_irq_unmask(uint32_t base, sdrv_smc_core_e core, uint32_t group,
uint32_t unmask)
{
uint32_t v, offset;
offset = sdrv_smc_get_common_irq_mask_offset(core, group);
v = sdrv_smc_readl(base, offset);
v &= ~unmask;
sdrv_smc_writel(base, offset, v);
}
static void sdrv_smc_clear_core_interrupt_monitor(uint32_t base, sdrv_smc_core_e core,
uint16_t clear_bitmap)
{
uint32_t v = sdrv_smc_readl(base, CORE_IRQ_MON_OFF(core));
v &= ~clear_bitmap;
sdrv_smc_writel(base, CORE_IRQ_MON_OFF(core), v);
}
static void sdrv_smc_clear_common_interrupt_monitor(uint32_t base, uint32_t grp,
uint32_t clear_bitmap)
{
if (grp < 8) {
uint32_t offset = COM_IRQ_MON_0_OFF + grp * 0x4;
uint32_t v = sdrv_smc_readl(base, offset);
v &= ~clear_bitmap;
sdrv_smc_writel(base, offset, v);
}
}
/**
* @brief Config Safety/AP domain global control setting.
*
* @param [in] smc_ctrl SMC controller instance.
* @param [in] config global control setting.
*/
status_t sdrv_smc_ctrl_global_control_config(sdrv_smc_t *smc_ctrl, sdrv_smc_global_control_t *config)
{
uint32_t base, v;
sdrv_smc_ctrl_set_primary_core(smc_ctrl, SDRV_SMC_SAF, config->saf_pri_core);
sdrv_smc_ctrl_set_primary_core(smc_ctrl, SDRV_SMC_AP, config->ap_pri_core);
sdrv_smc_ctrl_ap_domain_handshake(smc_ctrl, !config->ap_off_en);
base = (uint32_t)smc_ctrl->base;
v = sdrv_smc_readl(base, AP_GLB_CTL_OFF);
if (config->lp_align_saf_en) {
v |= BM_AP_GLB_CTL_LP_ALIGN2SAF;
}
else {
v &= ~BM_AP_GLB_CTL_LP_ALIGN2SAF;
}
if (config->wkup_align_saf_en) {
v |= BM_AP_GLB_CTL_WKUP_ALIGN2SAF;
}
else {
v &= ~BM_AP_GLB_CTL_WKUP_ALIGN2SAF;
}
sdrv_smc_writel(base, AP_GLB_CTL_OFF, v);
return SDRV_STATUS_OK;
}
/**
* @brief Set primary core id for a power domain.
*
* This function sets primary core id for a domain. Only the primary CPU of
* one domain can configure SMC registers of this domain.
*
* @param [in] smc_ctrl SMC controller instance
* @param [in] domain Safety or AP domain
* @param [in] id core id
*/
status_t sdrv_smc_ctrl_set_primary_core(sdrv_smc_t *smc_ctrl, sdrv_smc_domain_e domain, sdrv_smc_core_e id)
{
uint32_t base = (uint32_t)smc_ctrl->base;
if (domain == SDRV_SMC_SAF) {
uint32_t v = sdrv_smc_readl(base, SAF_GLB_CTL_OFF);
v &= ~FM_SAF_GLB_CTL_PRI_CORE;
v |= FV_SAF_GLB_CTL_PRI_CORE(id);
sdrv_smc_writel(base, SAF_GLB_CTL_OFF, v);
} else if (domain == SDRV_SMC_AP) {
uint32_t v = sdrv_smc_readl(base, AP_GLB_CTL_OFF);
v &= ~FM_AP_GLB_CTL_PRI_CORE;
v |= FV_AP_GLB_CTL_PRI_CORE(id);
sdrv_smc_writel(base, AP_GLB_CTL_OFF, v);
}
return SDRV_STATUS_OK;
}
/**
* @brief Set low power mode for specific domain.
*
* This function sets the low power mode of specific domain. The domain will
* enter required low power mode after its primary CPU and all CPUs belongs
* to this domain enters WFI.
*
* @param [in] smc_ctrl SMC controller instance
* @param [in] domain Safety or AP domain
* @param [in] mode Sleep or hibernate after primary CPU WFI
*/
status_t sdrv_smc_ctrl_set_lowpower_mode(sdrv_smc_t *smc_ctrl, sdrv_smc_domain_e domain, sdrv_smc_mode_e mode)
{
uint32_t base = (uint32_t)smc_ctrl->base;
if (domain == SDRV_SMC_SAF) {
uint32_t v = sdrv_smc_readl(base, SAF_GLB_CTL_OFF);
v &= ~BM_SAF_GLB_CTL_LP_MODE;
if (mode == SDRV_SMC_HIBERNATE) {
v |= BM_SAF_GLB_CTL_LP_MODE;
}
sdrv_smc_writel(base, SAF_GLB_CTL_OFF, v);
} else if (domain == SDRV_SMC_AP) {
uint32_t v = sdrv_smc_readl(base, AP_GLB_CTL_OFF);
v &= ~BM_AP_GLB_CTL_LP_MODE;
if (mode == SDRV_SMC_HIBERNATE) {
v |= BM_AP_GLB_CTL_LP_MODE;
}
sdrv_smc_writel(base, AP_GLB_CTL_OFF, v);
}
return SDRV_STATUS_OK;
}
/**
* @brief Enable or disable low power for specific domain
*
* This function enable or disable low power mode for a domain. If enabled, when all
* CPUs enter wfi, SMC will start low power procedure.
*
* @param [in] smc_ctrl SMC controller instance
* @param [in] domain safety or ap domain
* @param [in] enable true/false
*/
status_t sdrv_smc_ctrl_lowpower_enable(sdrv_smc_t *smc_ctrl, sdrv_smc_domain_e domain, bool enable)
{
uint32_t base = (uint32_t)smc_ctrl->base;
if (domain == SDRV_SMC_SAF) {
uint32_t v = sdrv_smc_readl(base, SAF_GLB_CTL_OFF);
v &= ~BM_SAF_GLB_CTL_WFI_DIS;
if (!enable) {
v |= BM_SAF_GLB_CTL_WFI_DIS;
}
sdrv_smc_writel(base, SAF_GLB_CTL_OFF, v);
} else if (domain == SDRV_SMC_AP) {
uint32_t v = sdrv_smc_readl(base, AP_GLB_CTL_OFF);
v &= ~BM_AP_GLB_CTL_WFI_DIS;
if (!enable) {
v |= BM_AP_GLB_CTL_WFI_DIS;
}
sdrv_smc_writel(base, AP_GLB_CTL_OFF, v);
}
return SDRV_STATUS_OK;
}
/**
* @brief Control power switchs in low power mode.
*
* This function configures power switch states (on or off) in domain
* low power mode.
*
* @param [in] smc_ctrl SMC controller instance
* @param [in] power_switch The power switch to configure.
* @param [in] mode The SMC low power mode to configure the switch for.
* @param [in] power_down_enable True to turn off the switch in low power
* mode. False to leave the power switch on in lower power mode.
*/
status_t sdrv_smc_ctrl_power_switch_config(sdrv_smc_t *smc_ctrl, sdrv_smc_power_switch_e power_switch,
sdrv_smc_mode_e mode, bool power_down_enable)
{
uint32_t offset;
uint32_t v;
uint32_t base = (uint32_t)smc_ctrl->base;
offset = sdrv_smc_lp_ctl_addr(power_switch);
v = sdrv_smc_readl(base, offset);
if (power_down_enable) {
if (mode == SDRV_SMC_HIBERNATE) {
v |= BM_SAF_LP_CTL_HIB_PD_EN;
} else {
v |= BM_SAF_LP_CTL_SLP_PD_EN;
}
} else {
if (mode == SDRV_SMC_HIBERNATE) {
v &= ~BM_SAF_LP_CTL_HIB_PD_EN;
} else {
v &= ~BM_SAF_LP_CTL_SLP_PD_EN;
}
}
sdrv_smc_writel(base, offset, v);
return SDRV_STATUS_OK;
}
/**
* @brief Config Power switch in low power delay control.
*
* @param [in] smc_ctrl SMC controller instance.
* @param [in] power_switch The power switch to configure.
* @param [in] iso_en isolation enable delay between LP process start to X_iso_en pose.
* @param [in] pg power gate delay between X_iso_en pose to X_pwr_gate pose.
* @param [in] po power on delay between RUN process start to X_pwr_gate nege.
* @param [in] iso_dis isolation disable delay between X_pwr_gate nege to X_iso_en_nege.
*/
status_t sdrv_smc_ctrl_power_switch_delay_config(sdrv_smc_t *smc_ctrl, sdrv_smc_power_switch_e power_switch,
uint32_t iso_en, uint32_t pg, uint32_t po, uint32_t iso_dis)
{
uint32_t offset;
volatile uint32_t v;
uint32_t base = (uint32_t)smc_ctrl->base;
offset = sdrv_smc_lp_ctl_dly_addr(power_switch);
v = sdrv_smc_readl(base, offset);
v &= ~FM_SAF_LP_DLY_CTL_ISO_EN;
v &= ~FM_SAF_LP_DLY_CTL_PG;
v &= ~FM_SAF_LP_DLY_CTL_PO;
v &= ~FM_SAF_LP_DLY_CTL_ISO_DIS;
v |= FV_SAF_LP_DLY_CTL_ISO_EN(iso_en);
v |= FV_SAF_LP_DLY_CTL_PG(pg);
v |= FV_SAF_LP_DLY_CTL_PO(po);
v |= FV_SAF_LP_DLY_CTL_ISO_DIS(iso_dis);
sdrv_smc_writel(base, offset, v);
return SDRV_STATUS_OK;
}
/**
* @brief Configure low power modes for core RAM
*
* This function configures low power modes for core RAMs, i.e, module interal
* RAM, CPU cache and TCM, in SMC sleep or hibernate modes.
*
* @param [in] smc_ctrl SMC controller instance
* @param [in] ram RAM type.
* @param [in] mode The SMC low power mode to configure RAM mode for.
* @param [in] ram_mode RAM mode in SMC low power mode. Possible values are:
* SDRV_SMC_CHIP_ENABLE
* SDRV_SMC_SELECTIVE_PRECHARGE
* SDRV_SMC_RETENTION_1
* SDRV_SMC_RETENTION_2
* SDRV_SMC_POWER_DOWN
*/
status_t sdrv_smc_ctrl_ram_lowpower_config(sdrv_smc_t *smc_ctrl, sdrv_smc_ram_e ram, sdrv_smc_mode_e mode,
uint32_t ram_mode)
{
uint32_t offset;
uint32_t v;
uint32_t base = (uint32_t)smc_ctrl->base;
offset = sdrv_smc_ram_lp_ctl_addr(ram);
v = sdrv_smc_readl(base, offset);
if (mode == SDRV_SMC_SLEEP) {
v &= ~BM_SAF_RAM_LP_CTL_SLP_RAM_PD_EN;
if (ram_mode != SDRV_SMC_CHIP_ENABLE) {
v |= BM_SAF_RAM_LP_CTL_SLP_RAM_PD_EN;
}
v &= ~FM_SAF_RAM_LP_CTL_SLP_RAM_LP_SETTING;
v |= FV_SAF_RAM_LP_CTL_SLP_RAM_LP_SETTING(ram_mode);
} else if (mode == SDRV_SMC_HIBERNATE) {
v &= ~BM_SAF_RAM_LP_CTL_HIB_RAM_PD_EN;
if (ram_mode != SDRV_SMC_CHIP_ENABLE) {
v |= BM_SAF_RAM_LP_CTL_HIB_RAM_PD_EN;
}
v &= ~FM_SAF_RAM_LP_CTL_HIB_RAM_LP_SETTING;
v |= FV_SAF_RAM_LP_CTL_HIB_RAM_LP_SETTING(ram_mode);
}
sdrv_smc_writel(base, offset, v);
return SDRV_STATUS_OK;
}
/**
* @brief Config SMC Saf or AP domain tiemout setting.
*
* @param [in] smc_ctrl SMC controller instance.
* @param [in] domain SDRV_SMC_SAF or SDRV_SMC_AP.
* @param [in] config domain timeout setting.
*/
status_t sdrv_smc_ctrl_domain_timeout_config(sdrv_smc_t *smc_ctrl, sdrv_smc_domain_e domain,
sdrv_smc_domain_timeout_t *config)
{
uint32_t offset;
volatile uint32_t v;
uint32_t base;
base = (uint32_t)smc_ctrl->base;
offset = (domain == SDRV_SMC_SAF) ? SAF_TIMEOUT_OFF : AP_TIMEOUT_OFF;
v = sdrv_smc_readl(base, offset);
if (config->wkup_en) {
v |= BM_SAF_TIMEOUT_WKUP_EN;
}
else {
v &= ~BM_SAF_TIMEOUT_WKUP_EN;
}
if (config->wdt_en) {
v |= BM_SAF_TIMEOUT_WDT_EN;
}
else {
v &= ~BM_SAF_TIMEOUT_WDT_EN;
}
v &= ~FM_SAF_TIMEOUT_CKGEN_HK;
v &= ~FM_SAF_TIMEOUT_RSTGEN_HK;
v &= ~FM_SAF_TIMEOUT_MODE_REQ_TRANS;
v |= FV_SAF_TIMEOUT_CKGEN_HK(config->ckgen_hk);
v |= FV_SAF_TIMEOUT_RSTGEN_HK(config->rstgen_hk);
v |= FV_SAF_TIMEOUT_MODE_REQ_TRANS(config->mode_req_trans);
sdrv_smc_writel(base, offset, v);
return SDRV_STATUS_OK;
}
/**
* @brief Config SMC Saf or AP domain misc.
*
* @param [in] smc_ctrl SMC controller instance.
* @param [in] domain SDRV_SMC_SAF or SDRV_SMC_AP.
* @param [in] lp_trans_req LP mode transition request.
* @param [in] irq_mask_dly Interrupt mask delay.
* @param [in] ill_trans_wkup_en Swm illegal transfer wakeup enable.
*/
status_t sdrv_smc_ctrl_domain_misc_config(sdrv_smc_t *smc_ctrl, sdrv_smc_domain_e domain,
bool lp_trans_req, uint32_t irq_mask_dly, bool ill_trans_wkup_en)
{
uint32_t offset;
volatile uint32_t v;
uint32_t base;
base = (uint32_t)smc_ctrl->base;
offset = (domain == SDRV_SMC_SAF) ? SAF_MISC_OFF : AP_MISC_OFF;
v = sdrv_smc_readl(base, offset);
v &= ~BM_SAF_MISC_LP_TRANS_REQ;
v &= ~FM_SAF_MISC_IRQ_MASK_DLY;
v &= ~BM_SAF_MISC_ILL_TRANS_WKUP_EN;
if (lp_trans_req) {
v |= BM_SAF_MISC_LP_TRANS_REQ;
}
if (ill_trans_wkup_en) {
v |= BM_SAF_MISC_ILL_TRANS_WKUP_EN;
}
v |= FV_SAF_MISC_IRQ_MASK_DLY(irq_mask_dly);
sdrv_smc_writel(base, offset, v);
return SDRV_STATUS_OK;
}
/**
* @brief AP domain smc config
*
* This function configures whether AP power state has impacts to the
* SMC state machine.
*
* @param [in] smc_ctrl SMC controller instance
* @param [in] ap_bitmap OR'ed value of the following macros:
* SDRV_SMC_IGNORE_AP
* SDRV_SMC_AP_LP_ALIGN_SAF
* SDRV_SMC_AP_WK_ALIGN_SAF
*/
status_t sdrv_smc_ctrl_ap_domain_config(sdrv_smc_t *smc_ctrl, uint32_t ap_bitmap)
{
uint32_t v;
uint32_t base = (uint32_t)smc_ctrl->base;
v = sdrv_smc_readl(base, AP_GLB_CTL_OFF);
v &= ~BM_AP_GLB_CTL_LP_ALIGN2SAF;
v &= ~BM_AP_GLB_CTL_WKUP_ALIGN2SAF;
sdrv_smc_writel(base, AP_GLB_CTL_OFF, v);
if (ap_bitmap & SDRV_SMC_IGNORE_AP) {
v = sdrv_smc_readl(base, SOC_GLB_CTL_OFF);
v |= BM_SOC_GLB_CTL_AP_OFF;
sdrv_smc_writel(base, SOC_GLB_CTL_OFF, v);
} else {
v = sdrv_smc_readl(base, SOC_GLB_CTL_OFF);
v &= ~BM_SOC_GLB_CTL_AP_OFF;
sdrv_smc_writel(base, SOC_GLB_CTL_OFF, v);
v = sdrv_smc_readl(base, AP_GLB_CTL_OFF);
if (ap_bitmap & SDRV_SMC_AP_LP_ALIGN_SAF) {
v |= BM_AP_GLB_CTL_LP_ALIGN2SAF;
}
if (ap_bitmap & SDRV_SMC_AP_WK_ALIGN_SAF) {
v |= BM_AP_GLB_CTL_WKUP_ALIGN2SAF;
}
sdrv_smc_writel(base, AP_GLB_CTL_OFF, v);
}
return SDRV_STATUS_OK;
}
/**
* @brief Configure RC oscillator state in hibernate mode.
*
* This function configures on chip 24M RC oscillator state in SMC
* hibernate mode.
*
* @param [in] smc_ctrl SMC controller instance
* @param [in] enable True to enable the RC oscillator in hibernate mode.
* False to turn off the oscillator in hibernate mode.
*/
status_t sdrv_smc_ctrl_rc24m_hibernate_enable(sdrv_smc_t *smc_ctrl, bool enable)
{
uint32_t base = (uint32_t)smc_ctrl->base;
uint32_t v;
v = sdrv_smc_readl(base, SOC_HIB_RC_DIS_OFF);
if (enable) {
v &= ~BM_SOC_HIB_RC_DIS_RC_DIS_EN;
} else {
v |= BM_SOC_HIB_RC_DIS_RC_DIS_EN;
}
sdrv_smc_writel(base, SOC_HIB_RC_DIS_OFF, v);
return SDRV_STATUS_OK;
}
/**
* @brief Set pre-divider number for 24M and 32K clock.
*
* @param [in] smc_ctrl SMC controller instance.
* @param [in] div_32k pre div number for clk32k.
* @param [in] div_24m pre div number for clk24m.
*/
status_t sdrv_smc_ctrl_pre_divider_config(sdrv_smc_t *smc_ctrl, uint16_t div_32k, uint8_t div_24m)
{
uint32_t base = (uint32_t)smc_ctrl->base;
uint32_t v;
v = sdrv_smc_readl(base, SOC_PRE_DIV_OFF);
v &= ~FM_SOC_PRE_DIV_DIV_NUM_32K;
v &= ~FM_SOC_PRE_DIV_DIV_NUM_24M;
v |= FV_SOC_PRE_DIV_DIV_NUM_32K(div_32k);
v |= FV_SOC_PRE_DIV_DIV_NUM_24M(div_24m);
sdrv_smc_writel(base, SOC_PRE_DIV_OFF, v);
return SDRV_STATUS_OK;
}
/**
* @brief Set soc swm timeout setting.
*
* @param [in] smc_ctrl SMC controller instance.
* @param [in] config soc timeout settings.
*/
status_t sdrv_smc_ctrl_soc_swm_timeout_config(sdrv_smc_t *smc_ctrl, sdrv_smc_soc_timeout_t *config)
{
uint32_t base = (uint32_t)smc_ctrl->base;
uint32_t v;
v = sdrv_smc_readl(base, SOC_SWM_TIMEOUT_OFF);
if (config->wkup_en) {
v |= BM_SOC_SWM_TIMEOUT_WKUP_EN;
}
else {
v &= ~BM_SOC_SWM_TIMEOUT_WKUP_EN;
}
if (config->wdt_en) {
v |= BM_SOC_SWM_TIMEOUT_WDT_EN;
}
else {
v &= ~BM_SOC_SWM_TIMEOUT_WDT_EN;
}
v &= ~FM_SOC_SWM_TIMEOUT_PMU_HK;
v |= FV_SOC_SWM_TIMEOUT_PMU_HK(config->pmu_hk);
sdrv_smc_writel(base, SOC_SWM_TIMEOUT_OFF, v);
return SDRV_STATUS_OK;
}
/**
* @brief Set soc wakeup control setting.
*
* @param [in] smc_ctrl SMC controller instance.
* @param [in] config soc wakeup control settings.
*/
status_t sdrv_smc_ctrl_soc_wakeup_control_config(sdrv_smc_t *smc_ctrl, sdrv_smc_soc_wakeup_ctrl_t *config)
{
uint32_t base = (uint32_t)smc_ctrl->base;
uint32_t v;
v = sdrv_smc_readl(base, SOC_WKUP_CTL_OFF);
if (config->lp2wkup_tout_wkup_en) {
v |= BM_SOC_WKUP_CTL_LP2WKUP_TOUT_WKUP_EN;
}
else {
v &= ~BM_SOC_WKUP_CTL_LP2WKUP_TOUT_WKUP_EN;
}
if (config->lp2wkup_wdt_en) {
v |= BM_SOC_WKUP_CTL_LP2WKUP_WDT_EN;
}
else {
v &= ~BM_SOC_WKUP_CTL_LP2WKUP_WDT_EN;
}
v &= ~FM_SOC_WKUP_CTL_LP2WKUP_VAL;
v |= FV_SOC_WKUP_CTL_LP2WKUP_VAL(config->lp2wkup_val);
if (config->wkup_wdt_en) {
v |= BM_SOC_WKUP_CTL_WKUP_WDT_EN;
}
else {
v &= ~BM_SOC_WKUP_CTL_WKUP_WDT_EN;
}
if (config->wkup_done_src_sel) {
v |= BM_SOC_WKUP_CTL_WKUP_DONE_SRC_SEL;
}
else {
v &= ~BM_SOC_WKUP_CTL_WKUP_DONE_SRC_SEL;
}
sdrv_smc_writel(base, SOC_WKUP_CTL_OFF, v);
v = sdrv_smc_readl(base, SOC_WKUP_TIMEOUT_OFF);
v &= ~FM_SOC_WKUP_TIMEOUT_WKUP_ACK;
v &= ~FM_SOC_WKUP_TIMEOUT_SOC_RUN;
v |= FV_SOC_WKUP_TIMEOUT_WKUP_ACK(config->wkup_ack_val);
v |= FV_SOC_WKUP_TIMEOUT_SOC_RUN(config->soc_run_val);
sdrv_smc_writel(base, SOC_WKUP_TIMEOUT_OFF, v);
return SDRV_STATUS_OK;
}
/**
* @brief Clear all core wakeup acknowledge.
*
* @param [in] smc_ctrl SMC controller instance.
*/
status_t sdrv_smc_ctrl_clear_core_wakeup_ack(sdrv_smc_t *smc_ctrl)
{
uint32_t base = (uint32_t)smc_ctrl->base;
uint32_t v;
v = sdrv_smc_readl(base, SOC_WKUP_CTL_OFF);
v &= ~FM_SOC_WKUP_CTL_SW_WKUP_ACK;
sdrv_smc_writel(base, SOC_WKUP_CTL_OFF, v);
return SDRV_STATUS_OK;
}
/**
* @brief Set core wakeup acknowledge.
*
* @param [in] smc_ctrl SMC controller instance.
* @param [in] ack bit0:cr5_saf, bit1:cr5_sp0, bit2:cr5_sp1, bit3:cr5_sx0, bit4:cr5_sx1
*/
status_t sdrv_smc_ctrl_set_core_wakeup_ack(sdrv_smc_t *smc_ctrl, uint32_t ack)
{
uint32_t base = (uint32_t)smc_ctrl->base;
uint32_t v;
v = sdrv_smc_readl(base, SOC_WKUP_CTL_OFF);
v |= FV_SOC_WKUP_CTL_SW_WKUP_ACK(ack);
sdrv_smc_writel(base, SOC_WKUP_CTL_OFF, v);
return SDRV_STATUS_OK;
}
/**
* @brief Set wakeup core irq enable or disable.
*
* @param [in] smc_ctrl SMC controller instance.
* @param [in] err_wkup smc error wakeup core irq enable
* bit0:cr5_saf, bit1:cr5_sp0, bit2:cr5_sp1, bit3:cr5_sx0, bit4:cr5_sx1
* @param [in] bk_wkup smc wakeup core irq enable
* bit0:cr5_saf, bit1:cr5_sp0, bit2:cr5_sp1, bit3:cr5_sx0, bit4:cr5_sx1
*/
status_t sdrv_smc_ctrl_core_wakeup_irq_config(sdrv_smc_t *smc_ctrl, uint32_t err_wkup, uint32_t bk_wkup)
{
uint32_t base = (uint32_t)smc_ctrl->base;
uint32_t v;
v = sdrv_smc_readl(base, SMC_WKUP_IRQ_OFF);
v &= ~FM_SMC_WKUP_IRQ_BK_WKUP_EN;
v &= ~FM_SMC_WKUP_IRQ_ERR_WKUP_EN;
v |= FV_SMC_WKUP_IRQ_ERR_WKUP_EN(err_wkup);
v |= FV_SMC_WKUP_IRQ_BK_WKUP_EN(bk_wkup);
sdrv_smc_writel(base, SMC_WKUP_IRQ_OFF, v);
return SDRV_STATUS_OK;
}
/**
* @brief Get wakeup core irq status.
*
* @param [in] smc_ctrl SMC controller instance.
* @return uint32_t bit0:cr5_saf, bit1:cr5_sp0, bit2:cr5_sp1, bit3:cr5_sx0, bit4:cr5_sx1
*/
uint32_t sdrv_smc_ctrl_get_core_wakeup_irq_status(sdrv_smc_t *smc_ctrl)
{
uint32_t base = (uint32_t)smc_ctrl->base;
uint32_t v;
v = sdrv_smc_readl(base, SMC_WKUP_IRQ_OFF);
return GFV_SMC_WKUP_IRQ_WKUP_IRQ_STA(v);
}
/**
* @brief Clear wakeup core irq status.
*
* @param [in] smc_ctrl SMC controller instance.
* @param [in] clr clear status bit.
* bit0:cr5_saf, bit1:cr5_sp0, bit2:cr5_sp1, bit3:cr5_sx0, bit4:cr5_sx1
*/
status_t sdrv_smc_ctrl_clear_core_wakeup_irq_status(sdrv_smc_t *smc_ctrl, uint32_t clr)
{
uint32_t base = (uint32_t)smc_ctrl->base;
uint32_t v;
v = sdrv_smc_readl(base, SMC_WKUP_IRQ_OFF);
v |= FV_SMC_WKUP_IRQ_WKUP_CLR(clr);
sdrv_smc_writel(base, SMC_WKUP_IRQ_OFF, v);
return SDRV_STATUS_OK;
}
/**
* @brief Config SOC misc.
*
* @param [in] smc_ctrl SMC controller instance.
* @param [in] ill_trans_wkup_en Swm illegal transfer wakeup enable.
*/
status_t sdrv_smc_ctrl_soc_misc_config(sdrv_smc_t *smc_ctrl, bool ill_trans_wkup_en)
{
uint32_t base = (uint32_t)smc_ctrl->base;
uint32_t v;
v = sdrv_smc_readl(base, SOC_MISC_OFF);
if (ill_trans_wkup_en) {
v |= BM_SOC_MISC_ILL_TRANS_WKUP_EN;
}
else {
v &= ~BM_SOC_MISC_ILL_TRANS_WKUP_EN;
}
sdrv_smc_writel(base, SOC_MISC_OFF, v);
return SDRV_STATUS_OK;
}
/**
* @brief Config SMC misc.
*
* @param [in] smc_ctrl SMC controller instance.
* @param [in] lpbk_force_check_en lpbk force check enable, loopback wdt div number check without req/ack active.
* @param [in] permission_err_en enable for permission error as apbslverr.
*/
status_t sdrv_smc_ctrl_smc_misc_config(sdrv_smc_t *smc_ctrl, bool lpbk_force_check_en, bool permission_err_en)
{
uint32_t base = (uint32_t)smc_ctrl->base;
uint32_t v;
v = sdrv_smc_readl(base, SMC_MISC_OFF);
if (lpbk_force_check_en) {
v |= (0x1U << 1);
}
else {
v &= ~(0x1U << 1);
}
if (permission_err_en) {
v |= (0x1U << 0);
}
else {
v &= ~(0x1U << 0);
}
sdrv_smc_writel(base, SMC_MISC_OFF, v);
return SDRV_STATUS_OK;
}
/**
* @brief Software trigger SMC handshake with other module.
*
* This function trigger SMC handshake with other module, after handshake
* successful, that module will in low power mode, it will use configuration
* in low power mode.
*
* @param [in] smc_ctrl SMC controller instance
* @param [in] handshake module to handshake
* @param [in] smc_swm system work mode, can be following macro:
* SDRV_SMC_SWM_RUN
* SDRV_SMC_SWM_SLP
* SDRV_SMC_SWM_HIB
* SDRV_SMC_SWM_RTC
*/
status_t sdrv_smc_ctrl_trigger_software_handshake(sdrv_smc_t *smc_ctrl, sdrv_smc_handshake_e handshake,
uint32_t smc_swm)
{
uint32_t base = (uint32_t)smc_ctrl->base;
uint32_t bit_s = handshake * 5;
uint32_t v = 0;
sdrv_smc_writel(base, SMC_SW_SWM_OFF, 0);
v |= ((smc_swm & 0x3) << (bit_s + 2));
v |= (0x3 << bit_s);
sdrv_smc_writel(base, SMC_SW_SWM_OFF, v);
v = sdrv_smc_readl(base, SMC_SW_SWM_OFF);
while (!(v & (0x1 << (bit_s + 4)))) {
v = sdrv_smc_readl(base, SMC_SW_SWM_OFF);
}
sdrv_smc_writel(base, SMC_SW_SWM_OFF, 0);
return SDRV_STATUS_OK;
}
/**
* @brief Software trigger SMC control power switch in run mode.
*
* This function can software override power switch value.
*
* @param [in] smc_ctrl SMC controller instance
* @param [in] power_switch The power switch to configure.
* @param [in] power_down_enable True to turn off the switch,
* False to turn on the switch.
*/
status_t sdrv_smc_ctrl_trigger_software_power_switch(sdrv_smc_t *smc_ctrl,
sdrv_smc_power_switch_e power_switch, bool power_down_enable)
{
uint32_t base = (uint32_t)smc_ctrl->base;
volatile uint32_t v;
uint32_t offset;
offset = sdrv_smc_lp_ctl_addr(power_switch);
v = sdrv_smc_readl(base, offset);
if (power_down_enable) {
v |= BM_SAF_LP_CTL_SW_PD_EN;
sdrv_smc_writel(base, offset, v);
v |= BM_SAF_LP_CTL_SW_ISO_EN;
sdrv_smc_writel(base, offset, v);
v |= BM_SAF_LP_CTL_SW_PWR_GATE;
sdrv_smc_writel(base, offset, v);
} else {
v &= ~BM_SAF_LP_CTL_SW_PWR_GATE;
sdrv_smc_writel(base, offset, v);
v &= ~BM_SAF_LP_CTL_SW_ISO_EN;
sdrv_smc_writel(base, offset, v);
v &= ~BM_SAF_LP_CTL_SW_PD_EN;
sdrv_smc_writel(base, offset, v);
}
return SDRV_STATUS_OK;
}
/**
* @brief Get power switch software power gate status.
*
* @param [in] smc_ctrl SMC controller instance
* @param [in] power_switch The power switch to read.
* @return Power gate status.
*/
bool sdrv_smc_ctrl_software_power_switch_gate_status(sdrv_smc_t *smc_ctrl, sdrv_smc_power_switch_e power_switch)
{
uint32_t base = (uint32_t)smc_ctrl->base;
uint32_t v;
uint32_t offset;
offset = sdrv_smc_lp_ctl_addr(power_switch);
v = sdrv_smc_readl(base, offset);
return (v & BM_SAF_LP_CTL_SW_PWR_GATE) == BM_SAF_LP_CTL_SW_PWR_GATE;
}
/**
* @brief Software trigger SMC control core ram power down in run mode.
*
* This function can software override core ram power down value.
*
* @param [in] smc_ctrl SMC controller instance
* @param [in] ram RAM type.
* @param [in] ram_mode RAM mode override by software. Possible values are:
* SDRV_SMC_CHIP_ENABLE
* SDRV_SMC_SELECTIVE_PRECHARGE
* SDRV_SMC_RETENTION_1
* SDRV_SMC_RETENTION_2
* SDRV_SMC_POWER_DOWN
*/
status_t sdrv_smc_ctrl_trigger_software_ram_lowpower(sdrv_smc_t *smc_ctrl, sdrv_smc_ram_e ram,
uint32_t ram_mode)
{
uint32_t base = (uint32_t)smc_ctrl->base;
uint32_t offset;
uint32_t v;
offset = sdrv_smc_ram_lp_ctl_addr(ram);
v = sdrv_smc_readl(base, offset);
v &= ~FM_SAF_RAM_LP_CTL_SW_RAM_LP_SETTING;
v |= FV_SAF_RAM_LP_CTL_SW_RAM_LP_SETTING(ram_mode);
sdrv_smc_writel(base, offset, v);
if (ram_mode != SDRV_SMC_CHIP_ENABLE) {
v |= BM_SAF_RAM_LP_CTL_SW_RAM_PD_EN;
}
else {
v &= ~BM_SAF_RAM_LP_CTL_SW_RAM_PD_EN;
}
sdrv_smc_writel(base, offset, v);
return SDRV_STATUS_OK;
}
/**
* @brief Get SWM status monitor register.
*
* This function get SOC/SAF/AP system work mode, futhermode,
* get SAF/AP internal system work mode.
*
* @param [in] smc_ctrl SMC controller instance
* @return uint32_t
* 0x1 Run, 0x2 Sleep, 0x4 Hibernate
* bit[3:0]-SAF_SWM, bit[7:4]-AP_SWM, bit[11:8]-SOC_SWM
* 0x1 Run, 0x2 LP Proc, 0x4 Run Proc, 0x8 LP
* bit[20:16]-SAF_INTER_SWM, bit[25:21]-AP_INTER_SWM
*/
uint32_t sdrv_smc_ctrl_status_monitor(sdrv_smc_t *smc_ctrl)
{
uint32_t base = (uint32_t)smc_ctrl->base;
return sdrv_smc_readl(base, SWM_MON_OFF);
}
/**
* @brief Clear SMC timeout and illegal transition error status.
*
* @param [in] smc_ctrl SMC controller instance
*/
status_t sdrv_smc_ctrl_clear_timeout_illegal_status(sdrv_smc_t *smc_ctrl)
{
uint32_t base = (uint32_t)smc_ctrl->base;
sdrv_smc_writel(base, SMC_TOUT_STA_OFF, 0);
sdrv_smc_writel(base, SMC_ILL_TRANS_STA_OFF, 0);
return SDRV_STATUS_OK;
}
/**
* @brief Get SMC timeout event monitor status.
*
* @param [in] smc_ctrl SMC controller instance
* @return uint32_t
*/
uint32_t sdrv_smc_ctrl_timeout_status_monitor(sdrv_smc_t *smc_ctrl)
{
uint32_t base = (uint32_t)smc_ctrl->base;
return sdrv_smc_readl(base, SMC_TOUT_STA_OFF);
}
/**
* @brief Get SMC illegal transition event monitor status.
*
* @param [in] smc_ctrl SMC controller instance
* @return uint32_t
*/
uint32_t sdrv_smc_ctrl_illegal_status_monitor(sdrv_smc_t *smc_ctrl)
{
uint32_t base = (uint32_t)smc_ctrl->base;
return sdrv_smc_readl(base, SMC_ILL_TRANS_STA_OFF);
}
/**
* @brief Mask all interrupt for SMC.
*
* This function mask all interrupt source in low power mode.
*
* @param [in] smc_ctrl SMC controller instance
*/
status_t sdrv_smc_ctrl_all_wakeup_interrupt_disable(sdrv_smc_t *smc_ctrl)
{
uint32_t base = (uint32_t)smc_ctrl->base;
for (uint32_t core = 0; core <= SDRV_SMC_CORE_SX1; core++) {
sdrv_smc_core_irq_mask(base, (sdrv_smc_core_e)core, 0xFFFF);
for (uint32_t grp = 0; grp < 8; grp++) {
sdrv_smc_common_irq_mask(base, (sdrv_smc_core_e)core, grp, 0xFFFFFFFF);
}
}
return SDRV_STATUS_OK;
}
/**
* @brief Enable wakeup interrupt for specific core.
*
* This function enable interrupt to wakeup specific core in low power mode.
*
* @param [in] smc_ctrl SMC controller instance
* @param [in] core core id
* @param [in] irq_num irq number
*/
status_t sdrv_smc_ctrl_wakeup_interrupt_enable(sdrv_smc_t *smc_ctrl, sdrv_smc_core_e core, uint32_t irq_num)
{
uint32_t base = (uint32_t)smc_ctrl->base;
if (irq_num < (256 + 16)) {
if (irq_num < 16) {
sdrv_smc_core_irq_unmask(base, core, 0x1U << irq_num);
} else {
irq_num -= 16;
sdrv_smc_common_irq_unmask(base, core, irq_num / 32,
0x1U << (irq_num % 32));
}
}
return SDRV_STATUS_OK;
}
/**
* @brief Disable wakeup interrupt for specific core.
*
* This function disable interrupt to wakeup specific core in low power mode.
*
* @param [in] smc_ctrl SMC controller instance
* @param [in] core core id
* @param [in] irq_num irq number
*/
status_t sdrv_smc_ctrl_wakeup_interrupt_disable(sdrv_smc_t *smc_ctrl, sdrv_smc_core_e core, uint32_t irq_num)
{
uint32_t base = (uint32_t)smc_ctrl->base;
if (irq_num < (256 + 16)) {
if (irq_num < 16) {
sdrv_smc_core_irq_mask(base, core, 0x1U << irq_num);
} else {
irq_num -= 16;
sdrv_smc_common_irq_mask(base, core, irq_num / 32,
0x1U << (irq_num % 32));
}
}
return SDRV_STATUS_OK;
}
/**
* @brief Clear all interrupt monitor register status.
*
* This function will clear all interrupt status in interrupt monitor register.
*
* @param [in] smc_ctrl SMC controller instance
*/
status_t sdrv_smc_ctrl_all_interrupt_monitor_clear(sdrv_smc_t *smc_ctrl)
{
uint32_t base = (uint32_t)smc_ctrl->base;
for (uint32_t core = 0; core <= SDRV_SMC_CORE_SX1; core++) {
sdrv_smc_clear_core_interrupt_monitor(base, (sdrv_smc_core_e)core, 0xFFFF);
}
for (uint32_t grp = 0; grp < 8; grp++) {
sdrv_smc_clear_common_interrupt_monitor(base, grp, 0xFFFFFFFF);
}
return SDRV_STATUS_OK;
}
/**
* @brief Get specific core interrupt status in interrupt monitor register.
*
* This function get the interrupt status for specific core.
*
* @param [in] smc_ctrl SMC controller instance
* @param [in] core core id
* @param [in] irq_num irq number
* @return true represents irq occurs, false represents no interrupt occurs.
*/
bool sdrv_smc_ctrl_interrupt_monitor_status(sdrv_smc_t *smc_ctrl, sdrv_smc_core_e core, uint32_t irq_num)
{
uint32_t base = (uint32_t)smc_ctrl->base;
if (irq_num < (256 + 16)) {
uint32_t v;
if (irq_num < 16) {
v = sdrv_smc_readl(base, CORE_IRQ_MON_OFF(core));
return !!(v & (0x1U << irq_num));
} else {
irq_num -= 16;
v = sdrv_smc_readl(base, COM_IRQ_MON_0_OFF + (irq_num / 32) * 0x4);
return !!(v & (0x1U << (irq_num % 32)));
}
} else {
return false;
}
}
/**
* @brief Clear specific core interrupt status in interrupt monitor register.
*
* This function clear the interrupt status for specific core.
*
* @param [in] smc_ctrl SMC controller instance
* @param [in] core core id
* @param [in] irq_num irq number
*/
status_t sdrv_smc_ctrl_clear_interrupt_monitor_status(sdrv_smc_t *smc_ctrl, sdrv_smc_core_e core,
uint32_t irq_num)
{
uint32_t base = (uint32_t)smc_ctrl->base;
if (irq_num < (256 + 16)) {
if (irq_num < 16) {
sdrv_smc_clear_core_interrupt_monitor(base, core, 0x1U << irq_num);
} else {
irq_num -= 16;
sdrv_smc_clear_common_interrupt_monitor(base, irq_num / 32,
0x1U << (irq_num % 32));
}
}
return SDRV_STATUS_OK;
}
/**
* @brief This function record monitor interrupt status when exit WFI.
*
* @param [in] smc_ctrl SMC controller instance
*/
status_t sdrv_smc_ctrl_record_interrupt_monitor_status(sdrv_smc_t *smc_ctrl)
{
uint32_t base = (uint32_t)smc_ctrl->base;
for (uint32_t i = 0; i < ARRAY_SIZE(smc_ctrl->core_irq_status); i++) {
smc_ctrl->core_irq_status[i] = sdrv_smc_readl(base, CORE_IRQ_MON_OFF(i));
}
for (uint32_t i = 0; i < ARRAY_SIZE(smc_ctrl->group_irq_status); i++) {
smc_ctrl->group_irq_status[i] = sdrv_smc_readl(base, COM_IRQ_MON_0_OFF + i * 0x4);
}
return SDRV_STATUS_OK;
}
/**
* @brief Config SMC whether handshake with AP domain.
*
* This function config SMC ignore AP domain.
*
* @param [in] smc_ctrl SMC controller instance
* @param [in] enable true represents SMC will handshake with AP,
* false represents SMC will not handshake with AP.
*/
status_t sdrv_smc_ctrl_ap_domain_handshake(sdrv_smc_t *smc_ctrl, bool enable)
{
uint32_t base = (uint32_t)smc_ctrl->base;
if (enable) {
sdrv_smc_writel(base, SOC_GLB_CTL_OFF, 0);
} else {
sdrv_smc_writel(base, SOC_GLB_CTL_OFF, 1);
}
return SDRV_STATUS_OK;
}
/**
* @brief Debug for SMC status.
*
* This function choose a debug output type, and return the debug value.
*
* @param [in] smc_ctrl SMC controller instance.
* @param [in] dbg_mux mux defined in sdrv_smc_debug_mux_e.
* @return uint32_t
*/
uint32_t sdrv_smc_ctrl_debug_monitor(sdrv_smc_t *smc_ctrl, sdrv_smc_debug_mux_e dbg_mux)
{
uint32_t ret;
uint32_t base;
base = (uint32_t)smc_ctrl->base;
sdrv_smc_writel(base, SMC_DBG_SEL_OFF, FV_SMC_DBG_SEL_SEL(dbg_mux));
ret = sdrv_smc_readl(base, SMC_DBG_MON_OFF);
sdrv_smc_writel(base, SMC_DBG_SEL_OFF, 0x0);
return ret;
}
/**
* @brief Config Safety/AP domain global control setting.
*
* @param [in] config global control setting.
*/
status_t sdrv_smc_global_control_config(sdrv_smc_global_control_t *config)
{
return sdrv_smc_ctrl_global_control_config(&g_default_smc_ctrl, config);
}
/**
* @brief Set primary core id for a power domain.
*
* This function sets primary core id for a domain. Only the primary CPU of
* one domain can configure SMC registers of this domain.
*
* @param [in] domain Safety or AP domain
* @param [in] id core id
*/
status_t sdrv_smc_set_primary_core(sdrv_smc_domain_e domain, sdrv_smc_core_e id)
{
return sdrv_smc_ctrl_set_primary_core(&g_default_smc_ctrl, domain, id);
}
/**
* @brief Set low power mode for specific domain.
*
* This function sets the low power mode of specific domain. The domain will
* enter required low power mode after its primary CPU and all CPUs belongs
* to this domain enters WFI.
*
* @param [in] domain Safety or AP domain
* @param [in] mode Sleep or hibernate after primary CPU WFI
*/
status_t sdrv_smc_set_lowpower_mode(sdrv_smc_domain_e domain, sdrv_smc_mode_e mode)
{
return sdrv_smc_ctrl_set_lowpower_mode(&g_default_smc_ctrl, domain, mode);
}
/**
* @brief Enable or disable low power for specific domain
*
* This function enable or disable low power mode for a domain. If enabled, when all
* CPUs enter wfi, SMC will start low power procedure.
*
* @param [in] domain safety or ap domain
* @param [in] enable true/false
*/
status_t sdrv_smc_lowpower_enable(sdrv_smc_domain_e domain, bool enable)
{
return sdrv_smc_ctrl_lowpower_enable(&g_default_smc_ctrl, domain, enable);
}
/**
* @brief Control power switchs in low power mode.
*
* This function configures power switch states (on or off) in domain
* low power mode.
*
* @param [in] power_switch The power switch to configure.
* @param [in] mode The SMC low power mode to configure the switch for.
* @param [in] power_down_enable True to turn off the switch in low power
* mode. False to leave the power switch on in lower power mode.
*/
status_t sdrv_smc_power_switch_config(sdrv_smc_power_switch_e power_switch,
sdrv_smc_mode_e mode, bool power_down_enable)
{
return sdrv_smc_ctrl_power_switch_config(&g_default_smc_ctrl, power_switch, mode, power_down_enable);
}
/**
* @brief Config Power switch in low power delay control.
*
* @param [in] power_switch The power switch to configure.
* @param [in] iso_en isolation enable delay between LP process start to X_iso_en pose.
* @param [in] pg power gate delay between X_iso_en pose to X_pwr_gate pose.
* @param [in] po power on delay between RUN process start to X_pwr_gate nege.
* @param [in] iso_dis isolation disable delay between X_pwr_gate nege to X_iso_en_nege.
*/
status_t sdrv_smc_power_switch_delay_config(sdrv_smc_power_switch_e power_switch,
uint32_t iso_en, uint32_t pg, uint32_t po, uint32_t iso_dis)
{
return sdrv_smc_ctrl_power_switch_delay_config(&g_default_smc_ctrl, power_switch, iso_en, pg, po, iso_dis);
}
/**
* @brief Configure low power modes for core RAM
*
* This function configures low power modes for core RAMs, i.e, module interal
* RAM, CPU cache and TCM, in SMC sleep or hibernate modes.
*
* @param [in] ram RAM type.
* @param [in] mode The SMC low power mode to configure RAM mode for.
* @param [in] ram_mode RAM mode in SMC low power mode. Possible values are:
* SDRV_SMC_CHIP_ENABLE
* SDRV_SMC_SELECTIVE_PRECHARGE
* SDRV_SMC_RETENTION_1
* SDRV_SMC_RETENTION_2
* SDRV_SMC_POWER_DOWN
*/
status_t sdrv_smc_ram_lowpower_config(sdrv_smc_ram_e ram, sdrv_smc_mode_e mode,
uint32_t ram_mode)
{
return sdrv_smc_ctrl_ram_lowpower_config(&g_default_smc_ctrl, ram, mode, ram_mode);
}
/**
* @brief Config SMC Saf or AP domain misc.
*
* @param [in] domain SDRV_SMC_SAF or SDRV_SMC_AP.
* @param [in] lp_trans_req LP mode transition request.
* @param [in] irq_mask_dly Interrupt mask delay.
* @param [in] ill_trans_wkup_en Swm illegal transfer wakeup enable.
*/
status_t sdrv_smc_domain_misc_config(sdrv_smc_domain_e domain,
bool lp_trans_req, uint32_t irq_mask_dly, bool ill_trans_wkup_en)
{
return sdrv_smc_ctrl_domain_misc_config(&g_default_smc_ctrl, domain, lp_trans_req, irq_mask_dly, ill_trans_wkup_en);
}
/**
* @brief Config SMC Saf or AP domain timeout setting.
*
* @param [in] domain SDRV_SMC_SAF or SDRV_SMC_AP.
* @param [in] config domain timeout setting config.
*/
status_t sdrv_smc_domain_timeout_config(sdrv_smc_domain_e domain, sdrv_smc_domain_timeout_t *config)
{
return sdrv_smc_ctrl_domain_timeout_config(&g_default_smc_ctrl, domain, config);
}
/**
* @brief AP domain smc config
*
* This function configures whether AP power state has impacts to the
* SMC state machine.
*
* @param [in] ap_bitmap OR'ed value of the following macros:
* SDRV_SMC_IGNORE_AP
* SDRV_SMC_AP_LP_ALIGN_SAF
* SDRV_SMC_AP_WK_ALIGN_SAF
*/
status_t sdrv_smc_ap_domain_config(uint32_t ap_bitmap)
{
return sdrv_smc_ctrl_ap_domain_config(&g_default_smc_ctrl, ap_bitmap);
}
/**
* @brief Configure RC oscillator state in hibernate mode.
*
* This function configures on chip 24M RC oscillator state in SMC
* hibernate mode.
*
* @param [in] enable True to enable the RC oscillator in hibernate mode.
* False to turn off the oscillator in hibernate mode.
*/
status_t sdrv_smc_rc24m_hibernate_enable(bool enable)
{
return sdrv_smc_ctrl_rc24m_hibernate_enable(&g_default_smc_ctrl, enable);
}
/**
* @brief Set pre-divider number for 24M and 32K clock.
*
* @param [in] div_32k pre div number for clk32k.
* @param [in] div_24m pre div number for clk24m.
*/
status_t sdrv_smc_pre_divider_config(uint16_t div_32k, uint8_t div_24m)
{
return sdrv_smc_ctrl_pre_divider_config(&g_default_smc_ctrl, div_32k, div_24m);
}
/**
* @brief Set soc swm timeout setting.
*
* @param [in] config soc timeout settings.
*/
status_t sdrv_smc_soc_swm_timeout_config(sdrv_smc_soc_timeout_t *config)
{
return sdrv_smc_ctrl_soc_swm_timeout_config(&g_default_smc_ctrl, config);
}
/**
* @brief Set soc wakeup control setting.
*
* @param [in] config soc wakeup control settings.
*/
status_t sdrv_smc_soc_wakeup_control_config(sdrv_smc_soc_wakeup_ctrl_t *config)
{
return sdrv_smc_ctrl_soc_wakeup_control_config(&g_default_smc_ctrl, config);
}
/**
* @brief Clear all core wakeup acknowledge.
*
*/
status_t sdrv_smc_clear_core_wakeup_ack(void)
{
return sdrv_smc_ctrl_clear_core_wakeup_ack(&g_default_smc_ctrl);
}
/**
* @brief Set core wakeup acknowledge.
*
* @param [in] ack bit0:cr5_saf, bit1:cr5_sp0, bit2:cr5_sp1, bit3:cr5_sx0, bit4:cr5_sx1
*/
status_t sdrv_smc_set_core_wakeup_ack(uint32_t ack)
{
return sdrv_smc_ctrl_set_core_wakeup_ack(&g_default_smc_ctrl, ack);
}
/**
* @brief Set wakeup core irq enable or disable.
*
* @param [in] err_wkup smc error wakeup core irq enable
* bit0:cr5_saf, bit1:cr5_sp0, bit2:cr5_sp1, bit3:cr5_sx0, bit4:cr5_sx1
* @param [in] bk_wkup smc wakeup core irq enable
* bit0:cr5_saf, bit1:cr5_sp0, bit2:cr5_sp1, bit3:cr5_sx0, bit4:cr5_sx1
*/
status_t sdrv_smc_core_wakeup_irq_config(uint32_t err_wkup, uint32_t bk_wkup)
{
return sdrv_smc_ctrl_core_wakeup_irq_config(&g_default_smc_ctrl, err_wkup, bk_wkup);
}
/**
* @brief Get wakeup core irq status.
*
* @return uint32_t bit0:cr5_saf, bit1:cr5_sp0, bit2:cr5_sp1, bit3:cr5_sx0, bit4:cr5_sx1
*/
uint32_t sdrv_smc_get_core_wakeup_irq_status(void)
{
return sdrv_smc_ctrl_get_core_wakeup_irq_status(&g_default_smc_ctrl);
}
/**
* @brief Clear wakeup core irq status.
*
* @param [in] clr clear status bit.
* bit0:cr5_saf, bit1:cr5_sp0, bit2:cr5_sp1, bit3:cr5_sx0, bit4:cr5_sx1
*/
status_t sdrv_smc_clear_core_wakeup_irq_status(uint32_t clr)
{
return sdrv_smc_ctrl_clear_core_wakeup_irq_status(&g_default_smc_ctrl, clr);
}
/**
* @brief Config SOC misc.
*
* @param [in] ill_trans_wkup_en Swm illegal transfer wakeup enable.
*/
status_t sdrv_smc_soc_misc_config(bool ill_trans_wkup_en)
{
return sdrv_smc_ctrl_soc_misc_config(&g_default_smc_ctrl, ill_trans_wkup_en);
}
/**
* @brief Config SMC misc.
*
* @param [in] lpbk_force_check_en lpbk force check enable, loopback wdt div number check without req/ack active.
* @param [in] permission_err_en enable for permission error as apbslverr.
*/
status_t sdrv_smc_smc_misc_config(bool lpbk_force_check_en, bool permission_err_en)
{
return sdrv_smc_ctrl_smc_misc_config(&g_default_smc_ctrl, lpbk_force_check_en, permission_err_en);
}
/**
* @brief Software trigger SMC handshake with other module.
*
* This function trigger SMC handshake with other module, after handshake
* successful, that module will in low power mode, it will use configuration
* in low power mode.
*
* @param [in] handshake module to handshake
* @param [in] smc_swm system work mode, can be following macro:
* SDRV_SMC_SWM_RUN
* SDRV_SMC_SWM_SLP
* SDRV_SMC_SWM_HIB
* SDRV_SMC_SWM_RTC
*/
status_t sdrv_smc_trigger_software_handshake(sdrv_smc_handshake_e handshake,
uint32_t smc_swm)
{
return sdrv_smc_ctrl_trigger_software_handshake(&g_default_smc_ctrl, handshake, smc_swm);
}
/**
* @brief Software trigger SMC control power switch in run mode.
*
* This function can software override power switch value.
*
* @param [in] power_switch The power switch to configure.
* @param [in] power_down_enable True to turn off the switch,
* False to turn on the switch.
*/
status_t sdrv_smc_trigger_software_power_switch(
sdrv_smc_power_switch_e power_switch, bool power_down_enable)
{
return sdrv_smc_ctrl_trigger_software_power_switch(&g_default_smc_ctrl, power_switch, power_down_enable);
}
/**
* @brief Get power switch software power gate status.
*
* @param [in] power_switch The power switch to read.
* @return Power gate status.
*/
bool sdrv_smc_software_power_switch_gate_status(sdrv_smc_power_switch_e power_switch)
{
return sdrv_smc_ctrl_software_power_switch_gate_status(&g_default_smc_ctrl, power_switch);
}
/**
* @brief Software trigger SMC control core ram power down in run mode.
*
* This function can software override core ram power down value.
*
* @param [in] ram RAM type.
* @param [in] ram_mode RAM mode override by software. Possible values are:
* SDRV_SMC_CHIP_ENABLE
* SDRV_SMC_SELECTIVE_PRECHARGE
* SDRV_SMC_RETENTION_1
* SDRV_SMC_RETENTION_2
* SDRV_SMC_POWER_DOWN
*/
status_t sdrv_smc_trigger_software_ram_lowpower(sdrv_smc_ram_e ram,
uint32_t ram_mode)
{
return sdrv_smc_ctrl_trigger_software_ram_lowpower(&g_default_smc_ctrl, ram, ram_mode);
}
/**
* @brief Get SWM status monitor register.
*
* This function get SOC/SAF/AP system work mode, futhermode,
* get SAF/AP internal system work mode.
*
* @return uint32_t
* 0x1 Run, 0x2 Sleep, 0x4 Hibernate
* bit[3:0]-SAF_SWM, bit[7:4]-AP_SWM, bit[11:8]-SOC_SWM
* 0x1 Run, 0x2 LP Proc, 0x4 Run Proc, 0x8 LP
* bit[20:16]-SAF_INTER_SWM, bit[25:21]-AP_INTER_SWM
*/
uint32_t sdrv_smc_status_monitor(void)
{
return sdrv_smc_ctrl_status_monitor(&g_default_smc_ctrl);
}
/**
* @brief Clear SMC timeout and illegal transition error status.
*/
status_t sdrv_smc_clear_timeout_illegal_status(void)
{
return sdrv_smc_ctrl_clear_timeout_illegal_status(&g_default_smc_ctrl);
}
/**
* @brief Get SMC timeout event monitor status.
*
* @return uint32_t
*/
uint32_t sdrv_smc_timeout_status_monitor(void)
{
return sdrv_smc_ctrl_timeout_status_monitor(&g_default_smc_ctrl);
}
/**
* @brief Get SMC illegal transition event monitor status.
*
* @return uint32_t
*/
uint32_t sdrv_smc_illegal_status_monitor(void)
{
return sdrv_smc_ctrl_illegal_status_monitor(&g_default_smc_ctrl);
}
/**
* @brief Mask all interrupt for SMC.
*
* This function mask all interrupt source in low power mode.
*/
status_t sdrv_smc_all_wakeup_interrupt_disable(void)
{
return sdrv_smc_ctrl_all_wakeup_interrupt_disable(&g_default_smc_ctrl);
}
/**
* @brief Enable wakeup interrupt for specific core.
*
* This function enable interrupt to wakeup specific core in low power mode.
*
* @param [in] core core id
* @param [in] irq_num irq number
*/
status_t sdrv_smc_wakeup_interrupt_enable(sdrv_smc_core_e core, uint32_t irq_num)
{
return sdrv_smc_ctrl_wakeup_interrupt_enable(&g_default_smc_ctrl, core, irq_num);
}
/**
* @brief Disable wakeup interrupt for specific core.
*
* This function disable interrupt to wakeup specific core in low power mode.
*
* @param [in] core core id
* @param [in] irq_num irq number
*/
status_t sdrv_smc_wakeup_interrupt_disable(sdrv_smc_core_e core, uint32_t irq_num)
{
return sdrv_smc_ctrl_wakeup_interrupt_disable(&g_default_smc_ctrl, core, irq_num);
}
/**
* @brief Clear all interrupt monitor register status.
*
* This function will clear all interrupt status in interrupt monitor register.
*/
status_t sdrv_smc_all_interrupt_monitor_clear(void)
{
return sdrv_smc_ctrl_all_interrupt_monitor_clear(&g_default_smc_ctrl);
}
/**
* @brief Get specific core interrupt status in interrupt monitor register.
*
* This function get the interrupt status for specific core.
*
* @param [in] core core id
* @param [in] irq_num irq number
* @return true represents irq occurs, false represents no interrupt occurs.
*/
bool sdrv_smc_interrupt_monitor_status(sdrv_smc_core_e core, uint32_t irq_num)
{
return sdrv_smc_ctrl_interrupt_monitor_status(&g_default_smc_ctrl, core, irq_num);
}
/**
* @brief Clear specific core interrupt status in interrupt monitor register.
*
* This function clear the interrupt status for specific core.
*
* @param [in] core core id
* @param [in] irq_num irq number
*/
status_t sdrv_smc_clear_interrupt_monitor_status(sdrv_smc_core_e core,
uint32_t irq_num)
{
return sdrv_smc_ctrl_clear_interrupt_monitor_status(&g_default_smc_ctrl, core, irq_num);
}
/**
* @brief This function record monitor interrupt status when exit WFI.
*
*/
status_t sdrv_smc_record_interrupt_monitor_status(void)
{
return sdrv_smc_ctrl_record_interrupt_monitor_status(&g_default_smc_ctrl);
}
/**
* @brief Config SMC whether handshake with AP domain.
*
* This function config SMC ignore AP domain.
*
* @param [in] enable true represents SMC will handshake with AP,
* false represents SMC will not handshake with AP.
*/
status_t sdrv_smc_ap_domain_handshake(bool enable)
{
return sdrv_smc_ctrl_ap_domain_handshake(&g_default_smc_ctrl, enable);
}
/**
* @brief Debug for SMC status.
*
* This function choose a debug output type, and return the debug value.
*
* @param [in] dbg_mux mux defined in sdrv_smc_debug_mux_e.
* @return uint32_t
*/
uint32_t sdrv_smc_debug_monitor(sdrv_smc_debug_mux_e dbg_mux)
{
return sdrv_smc_ctrl_debug_monitor(&g_default_smc_ctrl, dbg_mux);
}