/** * @file sdrv_smc.c * @brief Sdrv SMC driver source. * * @copyright Copyright (c) 2022 Semidrive Semiconductor. * All rights reserved. */ #include #include #include #include #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); }