/** * @file sdrv_power.c * @brief Sdrv power driver source. * * @copyright Copyright (c) 2022 Semidrive Semiconductor. * All rights reserved. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../clk/sdrv_ckgen_hw_access.h" #include "sdrv_power_core_context.h" #include "sdrv_dcdc_reg.h" #ifndef APB_USB0H_BASE #define APB_USB0H_BASE APB_USB_BASE #define APB_USB0D_BASE (APB_USB0H_BASE + 0x1000u) #endif // USB components base address #define USB_HOST_BASE_ADDR APB_USB0H_BASE #define USB_OTG_BASE_ADDR APB_USB0D_BASE #define USB_OTGNC_BASE_ADDR (USB_OTG_BASE_ADDR + 0x800) #define USB_PHYNC_BASE_ADDR (USB_OTGNC_BASE_ADDR + 0x100) #define PHY_NCR_CTL_0 (USB_PHYNC_BASE_ADDR + 0x0) #define PHY_NCR_CTL_6 (USB_PHYNC_BASE_ADDR + 0x18) #define PHY_NCR_CTL_9 (USB_PHYNC_BASE_ADDR + 0x24) #undef CKGEN_RUN_MODE #undef CKGEN_HIB_MODE #undef CKGEN_SLP_MODE #ifndef CLK_24M_RATE #define CLK_24M_RATE 24000000 #endif #define SDRV_POWER_POLL_COUNT 100000u #define SDRV_SMC_RUN_STATUS ((0x1U) | (0x1U << 4) | (0x1U << 8) | (0x1U << 16) | (0x1U << 21)) #if !CONFIG_RTC_SS_DYNAMIC_PCLK #define RTC_REG_PARITY_ERR_INT_EN() SDRV_RTC_REG_PARITY_ERR_ENABLE(); #define RTC_REG_PARITY_ERR_INT_DIS() SDRV_RTC_REG_PARITY_ERR_DISABLE(); #else #define RTC_REG_PARITY_ERR_INT_EN() #define RTC_REG_PARITY_ERR_INT_DIS() #endif #define SDRV_POWER_RSTSIG_NUM 4 /** * @brief iram low power mode * power down mode , data will be invalid, after power on, iram need init * other mode data will be stored, and retention2 mode is the lowest mode */ typedef enum sdrv_iram_lp { SDRV_IRAM_IDLE = 0U, SDRV_IRAM_PRECHARGE, SDRV_IRAM_RETENTION1, SDRV_IRAM_RETENTION2, SDRV_IRAM_POWER_DOWN, } sdrv_iram_lp_e; typedef struct sdrv_core_clk { uint32_t sf_rate; uint32_t sp_rate; uint32_t sx_rate; } sdrv_core_clk_t; typedef struct sdrv_ap_bus_clk { uint32_t ap_bus_rate; uint32_t disp_bus_rate; uint32_t seip_bus_rate; } sdrv_ap_bus_clk_t; typedef struct sdrv_soc_clk { sdrv_core_clk_t core_clks; sdrv_ap_bus_clk_t ap_bus_clks; } sdrv_soc_clk_t; typedef struct sdrv_power_ctrl { uint32_t iram_hib_pd_mask; uint32_t power_switch_hib_pd_mask; #if CONFIG_E3 || CONFIG_D3 uint32_t core_gama_rstsig; #endif sdrv_ap_bus_clk_t ap_bus_clks; sdrv_core_clk_t core_clks; sdrv_soc_clk_t soc_default_clks; sdrv_power_analog_t analog_cfg; sdrv_rstgen_sig_t *sleep_rstsig[SDRV_POWER_RSTSIG_NUM]; sdrv_rstgen_sig_t *hib_rstsig[SDRV_POWER_RSTSIG_NUM]; } sdrv_power_ctrl_t; static sdrv_power_ctrl_t g_power_ctrl; #if CONFIG_E3 || CONFIG_D3 static sdrv_ckgen_node_t *uarts_pcg[16][2] = { { CLK_NODE(g_ckgen_gating_uart1_pclk), CLK_NODE(g_ckgen_gating_uart1_sclk) }, { CLK_NODE(g_ckgen_gating_uart2_pclk), CLK_NODE(g_ckgen_gating_uart2_sclk) }, { CLK_NODE(g_ckgen_gating_uart3_pclk), CLK_NODE(g_ckgen_gating_uart3_sclk) }, { CLK_NODE(g_ckgen_gating_uart4_pclk), CLK_NODE(g_ckgen_gating_uart4_sclk) }, { CLK_NODE(g_ckgen_gating_uart5_pclk), CLK_NODE(g_ckgen_gating_uart5_sclk) }, { CLK_NODE(g_ckgen_gating_uart6_pclk), CLK_NODE(g_ckgen_gating_uart6_sclk) }, { CLK_NODE(g_ckgen_gating_uart7_pclk), CLK_NODE(g_ckgen_gating_uart7_sclk) }, { CLK_NODE(g_ckgen_gating_uart8_pclk), CLK_NODE(g_ckgen_gating_uart8_sclk) }, #ifdef APB_UART9_BASE { CLK_NODE(g_ckgen_gating_uart9_pclk), CLK_NODE(g_ckgen_gating_uart9_sclk) }, { CLK_NODE(g_ckgen_gating_uart10_pclk), CLK_NODE(g_ckgen_gating_uart10_sclk) }, { CLK_NODE(g_ckgen_gating_uart11_pclk), CLK_NODE(g_ckgen_gating_uart11_sclk) }, { CLK_NODE(g_ckgen_gating_uart12_pclk), CLK_NODE(g_ckgen_gating_uart12_sclk) }, #endif #ifdef APB_UART13_BASE { CLK_NODE(g_ckgen_gating_uart13_pclk), CLK_NODE(g_ckgen_gating_uart13_sclk) }, { CLK_NODE(g_ckgen_gating_uart14_pclk), CLK_NODE(g_ckgen_gating_uart14_sclk) }, { CLK_NODE(g_ckgen_gating_uart15_pclk), CLK_NODE(g_ckgen_gating_uart15_sclk) }, { CLK_NODE(g_ckgen_gating_uart16_pclk), CLK_NODE(g_ckgen_gating_uart16_sclk) }, #endif }; #ifdef APB_CANFD1_BASE static sdrv_ckgen_node_t *canfd1_2_pcg[][3] = { { CLK_NODE(g_ckgen_gating_canfd1_pclk), CLK_NODE(g_ckgen_gating_canfd1_ipg_clk), CLK_NODE(g_ckgen_gating_canfd1_clk24m) }, { CLK_NODE(g_ckgen_gating_canfd2_pclk), CLK_NODE(g_ckgen_gating_canfd2_ipg_clk), CLK_NODE(g_ckgen_gating_canfd2_clk24m) }, }; #endif #ifdef APB_CANFD3_BASE static sdrv_ckgen_node_t *canfd3_4_pcg[][3] = { { CLK_NODE(g_ckgen_gating_canfd3_pclk), CLK_NODE(g_ckgen_gating_canfd3_ipg_clk), CLK_NODE(g_ckgen_gating_canfd3_clk24m) }, { CLK_NODE(g_ckgen_gating_canfd4_pclk), CLK_NODE(g_ckgen_gating_canfd4_ipg_clk), CLK_NODE(g_ckgen_gating_canfd4_clk24m) }, }; #endif #ifdef APB_CANFD5_BASE static sdrv_ckgen_node_t *canfd5_6_pcg[][3] = { { CLK_NODE(g_ckgen_gating_canfd5_pclk), CLK_NODE(g_ckgen_gating_canfd5_ipg_clk), CLK_NODE(g_ckgen_gating_canfd5_clk24m) }, { CLK_NODE(g_ckgen_gating_canfd6_pclk), CLK_NODE(g_ckgen_gating_canfd6_ipg_clk), CLK_NODE(g_ckgen_gating_canfd6_clk24m) }, }; #endif #ifdef APB_CANFD7_BASE static sdrv_ckgen_node_t *canfd7_pcg[][3] = { { CLK_NODE(g_ckgen_gating_canfd7_pclk), CLK_NODE(g_ckgen_gating_canfd7_ipg_clk), CLK_NODE(g_ckgen_gating_canfd7_clk24m) }, }; #endif #ifdef APB_CANFD8_BASE static sdrv_ckgen_node_t *canfd8_15_pcg[][3] = { { CLK_NODE(g_ckgen_gating_canfd8_pclk), CLK_NODE(g_ckgen_gating_canfd8_ipg_clk), CLK_NODE(g_ckgen_gating_canfd8_clk24m) }, { CLK_NODE(g_ckgen_gating_canfd9_pclk), CLK_NODE(g_ckgen_gating_canfd9_ipg_clk), CLK_NODE(g_ckgen_gating_canfd9_clk24m) }, { CLK_NODE(g_ckgen_gating_canfd10_pclk), CLK_NODE(g_ckgen_gating_canfd10_ipg_clk), CLK_NODE(g_ckgen_gating_canfd10_clk24m) }, { CLK_NODE(g_ckgen_gating_canfd11_pclk), CLK_NODE(g_ckgen_gating_canfd11_ipg_clk), CLK_NODE(g_ckgen_gating_canfd11_clk24m) }, { CLK_NODE(g_ckgen_gating_canfd12_pclk), CLK_NODE(g_ckgen_gating_canfd12_ipg_clk), CLK_NODE(g_ckgen_gating_canfd12_clk24m) }, { CLK_NODE(g_ckgen_gating_canfd13_pclk), CLK_NODE(g_ckgen_gating_canfd13_ipg_clk), CLK_NODE(g_ckgen_gating_canfd13_clk24m) }, { CLK_NODE(g_ckgen_gating_canfd14_pclk), CLK_NODE(g_ckgen_gating_canfd14_ipg_clk), CLK_NODE(g_ckgen_gating_canfd14_clk24m) }, { CLK_NODE(g_ckgen_gating_canfd15_pclk), CLK_NODE(g_ckgen_gating_canfd15_ipg_clk), CLK_NODE(g_ckgen_gating_canfd15_clk24m) }, }; #endif #ifdef APB_CANFD16_BASE static sdrv_ckgen_node_t *canfd16_pcg[][3] = { { CLK_NODE(g_ckgen_gating_canfd16_pclk), CLK_NODE(g_ckgen_gating_canfd16_ipg_clk), CLK_NODE(g_ckgen_gating_canfd16_clk24m) }, }; #endif #ifdef APB_CANFD17_BASE static sdrv_ckgen_node_t *canfd17_20_pcg[][3] = { { CLK_NODE(g_ckgen_gating_canfd17_pclk), CLK_NODE(g_ckgen_gating_canfd17_ipg_clk), CLK_NODE(g_ckgen_gating_canfd17_clk24m) }, { CLK_NODE(g_ckgen_gating_canfd18_pclk), CLK_NODE(g_ckgen_gating_canfd18_ipg_clk), CLK_NODE(g_ckgen_gating_canfd18_clk24m) }, { CLK_NODE(g_ckgen_gating_canfd19_pclk), CLK_NODE(g_ckgen_gating_canfd19_ipg_clk), CLK_NODE(g_ckgen_gating_canfd19_clk24m) }, { CLK_NODE(g_ckgen_gating_canfd20_pclk), CLK_NODE(g_ckgen_gating_canfd20_ipg_clk), CLK_NODE(g_ckgen_gating_canfd20_clk24m) }, }; #endif #ifdef APB_CANFD21_BASE static sdrv_ckgen_node_t *canfd21_pcg[][3] = { { CLK_NODE(g_ckgen_gating_canfd21_pclk), CLK_NODE(g_ckgen_gating_canfd21_ipg_clk), CLK_NODE(g_ckgen_gating_canfd21_clk24m) }, }; #endif #ifdef APB_CANFD22_BASE static sdrv_ckgen_node_t *canfd22_pcg[][3] = { { CLK_NODE(g_ckgen_gating_canfd22_pclk), CLK_NODE(g_ckgen_gating_canfd22_ipg_clk), CLK_NODE(g_ckgen_gating_canfd22_clk24m) }, }; #endif #ifdef APB_CANFD23_BASE static sdrv_ckgen_node_t *canfd23_pcg[][3] = { { CLK_NODE(g_ckgen_gating_canfd23_pclk), CLK_NODE(g_ckgen_gating_canfd23_ipg_clk), CLK_NODE(g_ckgen_gating_canfd23_clk24m) }, }; #endif #ifdef APB_CANFD24_BASE static sdrv_ckgen_node_t *canfd24_pcg[][3] = { { CLK_NODE(g_ckgen_gating_canfd24_pclk), CLK_NODE(g_ckgen_gating_canfd24_ipg_clk), CLK_NODE(g_ckgen_gating_canfd24_clk24m) }, }; #endif #endif /* #if CONFIG_E3 || CONFIG_D3 */ #if CONFIG_E3L || CONFIG_D3L static sdrv_ckgen_node_t *uarts_pcg[12][2] = { { CLK_NODE(g_ckgen_gating_uart1_i_pclk), CLK_NODE(g_ckgen_gating_uart1_i_sclk) }, { CLK_NODE(g_ckgen_gating_uart2_i_pclk), CLK_NODE(g_ckgen_gating_uart2_i_sclk) }, { CLK_NODE(g_ckgen_gating_uart3_i_pclk), CLK_NODE(g_ckgen_gating_uart3_i_sclk) }, { CLK_NODE(g_ckgen_gating_uart4_i_pclk), CLK_NODE(g_ckgen_gating_uart4_i_sclk) }, { CLK_NODE(g_ckgen_gating_uart5_i_pclk), CLK_NODE(g_ckgen_gating_uart5_i_sclk) }, { CLK_NODE(g_ckgen_gating_uart6_i_pclk), CLK_NODE(g_ckgen_gating_uart6_i_sclk) }, { CLK_NODE(g_ckgen_gating_uart7_i_pclk), CLK_NODE(g_ckgen_gating_uart7_i_sclk) }, { CLK_NODE(g_ckgen_gating_uart8_i_pclk), CLK_NODE(g_ckgen_gating_uart8_i_sclk) }, #ifdef APB_UART9_BASE { CLK_NODE(g_ckgen_gating_uart9_i_pclk), CLK_NODE(g_ckgen_gating_uart9_i_sclk) }, { CLK_NODE(g_ckgen_gating_uart10_i_pclk), CLK_NODE(g_ckgen_gating_uart10_i_sclk) }, { CLK_NODE(g_ckgen_gating_uart11_i_pclk), CLK_NODE(g_ckgen_gating_uart11_i_sclk) }, { CLK_NODE(g_ckgen_gating_uart12_i_pclk), CLK_NODE(g_ckgen_gating_uart12_i_sclk) }, #endif }; #ifdef APB_CANFD16_BASE static sdrv_ckgen_node_t *canfd16_pcg[][3] = { { CLK_NODE(g_ckgen_gating_canfd16_pclk), CLK_NODE(g_ckgen_gating_canfd16_ipg_clk), CLK_NODE(g_ckgen_gating_canfd16_clk24m) }, }; #endif #ifdef APB_CANFD21_BASE static sdrv_ckgen_node_t *canfd21_pcg[][3] = { { CLK_NODE(g_ckgen_gating_canfd21_pclk), CLK_NODE(g_ckgen_gating_canfd21_ipg_clk), CLK_NODE(g_ckgen_gating_canfd21_clk24m) }, }; #endif #ifdef APB_CANFD3_BASE static sdrv_ckgen_node_t *canfd3_4_pcg[][3] = { { CLK_NODE(g_ckgen_gating_canfd3_pclk), CLK_NODE(g_ckgen_gating_canfd3_ipg_clk), CLK_NODE(g_ckgen_gating_canfd3_clk24m) }, { CLK_NODE(g_ckgen_gating_canfd4_pclk), CLK_NODE(g_ckgen_gating_canfd4_ipg_clk), CLK_NODE(g_ckgen_gating_canfd4_clk24m) }, }; #endif #ifdef APB_CANFD5_BASE static sdrv_ckgen_node_t *canfd5_6_pcg[][3] = { { CLK_NODE(g_ckgen_gating_canfd5_pclk), CLK_NODE(g_ckgen_gating_canfd5_ipg_clk), CLK_NODE(g_ckgen_gating_canfd5_clk24m) }, { CLK_NODE(g_ckgen_gating_canfd6_pclk), CLK_NODE(g_ckgen_gating_canfd6_ipg_clk), CLK_NODE(g_ckgen_gating_canfd6_clk24m) }, }; #endif #ifdef APB_CANFD7_BASE static sdrv_ckgen_node_t *canfd7_pcg[][3] = { { CLK_NODE(g_ckgen_gating_canfd7_pclk), CLK_NODE(g_ckgen_gating_canfd7_ipg_clk), CLK_NODE(g_ckgen_gating_canfd7_clk24m) }, }; #endif #ifdef APB_CANFD23_BASE static sdrv_ckgen_node_t *canfd23_pcg[][3] = { { CLK_NODE(g_ckgen_gating_canfd23_pclk), CLK_NODE(g_ckgen_gating_canfd23_ipg_clk), CLK_NODE(g_ckgen_gating_canfd23_clk24m) }, }; #endif static sdrv_ckgen_node_t *ap_mix_cgs[] = { CLK_NODE(g_ckgen_gating_fab_ap_apmainclk), CLK_NODE(g_ckgen_gating_fab_ap_perclk), CLK_NODE(g_ckgen_gating_apbmux4_pclk), CLK_NODE(g_ckgen_gating_saci2_pdm_per_clk), CLK_NODE(g_ckgen_gating_sehc1_main_clk), CLK_NODE(g_ckgen_gating_sehc1_aclk), CLK_NODE(g_ckgen_gating_seip_sh_clk), CLK_NODE(g_ckgen_gating_usb2_pclk), CLK_NODE(g_ckgen_gating_sehc1_pclk), CLK_NODE(g_ckgen_gating_saci2_pclk), CLK_NODE(g_ckgen_gating_seip_i_pclk), CLK_NODE(g_ckgen_gating_seip_i_hclk), CLK_NODE(g_ckgen_gating_seip_i_fd_ref_clk), CLK_NODE(g_ckgen_gating_saci2_i2s_mclk), CLK_NODE(g_ckgen_gating_saci2_ext_clk), CLK_NODE(g_ckgen_gating_saci2_i2s_tx_clk), CLK_NODE(g_ckgen_gating_saci2_i2s_rx_clk), CLK_NODE(g_ckgen_gating_usb_i_phy_ref_clk), CLK_NODE(g_ckgen_gating_sehc1_cqe_sqs_clk), CLK_NODE(g_ckgen_gating_sehc1_tm_clk), }; #endif /* #if CONFIG_E3L || CONFIG_D3L */ static inline bool sdrv_power_wait(uint32_t reg, uint32_t bit_shift, uint32_t expect, uint32_t count) { volatile uint32_t times_out = count; while ((times_out != 0u) && (expect != ((readl(reg) & ((uint32_t)1u << bit_shift)) >> bit_shift))) { times_out--; } return times_out > 0u ? true : false; } static void sdrv_power_all_xcg_gate_in_lowpower(uint32_t base, uint32_t pcg_num, uint32_t bcg_num, uint32_t ccg_num) { sdrv_ckgen_node_t ckgen_node; ckgen_node.base = base; ckgen_node.type = CKGEN_PCG_TYPE; for (ckgen_node.id = 0; ckgen_node.id < pcg_num; ckgen_node.id++) { sdrv_ckgen_set_gate(&ckgen_node, CKGEN_HIB_MODE, true); sdrv_ckgen_set_gate(&ckgen_node, CKGEN_SLP_MODE, true); } ckgen_node.type = CKGEN_BCG_TYPE; for (ckgen_node.id = 0; ckgen_node.id < bcg_num; ckgen_node.id++) { sdrv_ckgen_set_gate(&ckgen_node, CKGEN_HIB_MODE, true); sdrv_ckgen_set_gate(&ckgen_node, CKGEN_SLP_MODE, true); } ckgen_node.type = CKGEN_CCG_TYPE; for (ckgen_node.id = 0; ckgen_node.id < ccg_num; ckgen_node.id++) { sdrv_ckgen_set_gate(&ckgen_node, CKGEN_HIB_MODE, true); sdrv_ckgen_set_gate(&ckgen_node, CKGEN_SLP_MODE, true); } } #if CONFIG_E3 || CONFIG_D3 /** * @brief enable wakeup IP clock, and enable wakeup interrupt in SMC * * @param [in] source * @param [in] mode */ static void sdrv_power_enable_wakeup_source_pcg(sdrv_wakeup_src_e source, sdrv_power_mode_e mode) { sdrv_ckgen_lp_mode_e ckgen_mode; uint32_t irq_num = 0xFFFFFFFFU; if (mode == SDRV_SLEEP_MODE) { ckgen_mode = CKGEN_SLP_MODE; } else if (mode == SDRV_HIBERNATE_MODE) { ckgen_mode = CKGEN_HIB_MODE; } else { return; } switch (source) { case SDRV_WAKEUP_GPIO_SF: irq_num = SDRV_SMC_ASYNC_INT_VIC1_SF_GPIO; break; case SDRV_WAKEUP_GPIO_AP: irq_num = SDRV_SMC_ASYNC_INT_VIC1_AP_GPIO; break; case SDRV_WAKEUP_RTC1: irq_num = RTC1_RTC_WAKEUP_INTR_NUM; break; case SDRV_WAKEUP_RTC2: irq_num = RTC2_RTC_WAKEUP_INTR_NUM; break; case SDRV_WAKEUP_UART1...SDRV_WAKEUP_UART8: irq_num = UART1_INTR_NUM + (source - SDRV_WAKEUP_UART1); for (uint32_t i = 0; i < 2; i++) { sdrv_ckgen_set_gate(uarts_pcg[source - SDRV_WAKEUP_UART1][i], ckgen_mode, false); } break; #ifdef APB_UART9_BASE case SDRV_WAKEUP_UART9...SDRV_WAKEUP_UART12: irq_num = UART9_INTR_NUM + (source - SDRV_WAKEUP_UART9); for (uint32_t i = 0; i < 2; i++) { sdrv_ckgen_set_gate(uarts_pcg[source - SDRV_WAKEUP_UART1][i], ckgen_mode, false); } break; #endif #ifdef APB_UART13_BASE case SDRV_WAKEUP_UART13...SDRV_WAKEUP_UART16: irq_num = UART13_INTR_NUM + (source - SDRV_WAKEUP_UART13); for (uint32_t i = 0; i < 2; i++) { sdrv_ckgen_set_gate(uarts_pcg[source - SDRV_WAKEUP_UART1][i], ckgen_mode, false); } break; #endif #ifdef APB_CANFD1_BASE case SDRV_WAKEUP_CANFD1: case SDRV_WAKEUP_CANFD2: irq_num = CANFD1_CANFD_INTR_NUM + (source - SDRV_WAKEUP_CANFD1); for (uint32_t i = 0; i < 3; i++) { sdrv_ckgen_set_gate(canfd1_2_pcg[source - SDRV_WAKEUP_CANFD1][i], ckgen_mode, false); } break; #endif #ifdef APB_CANFD3_BASE case SDRV_WAKEUP_CANFD3: case SDRV_WAKEUP_CANFD4: irq_num = CANFD3_CANFD_INTR_NUM + (source - SDRV_WAKEUP_CANFD3); for (uint32_t i = 0; i < 3; i++) { sdrv_ckgen_set_gate(canfd3_4_pcg[source - SDRV_WAKEUP_CANFD3][i], ckgen_mode, false); } break; #endif #ifdef APB_CANFD5_BASE case SDRV_WAKEUP_CANFD5: case SDRV_WAKEUP_CANFD6: irq_num = CANFD5_CANFD_INTR_NUM + (source - SDRV_WAKEUP_CANFD5); for (uint32_t i = 0; i < 3; i++) { sdrv_ckgen_set_gate(canfd5_6_pcg[source - SDRV_WAKEUP_CANFD5][i], ckgen_mode, false); } break; #endif #ifdef APB_CANFD7_BASE case SDRV_WAKEUP_CANFD7: irq_num = CANFD7_CANFD_INTR_NUM; for (uint32_t i = 0; i < 3; i++) { sdrv_ckgen_set_gate(canfd7_pcg[0][i], ckgen_mode, false); } break; #endif #ifdef APB_CANFD8_BASE case SDRV_WAKEUP_CANFD8: case SDRV_WAKEUP_CANFD9: case SDRV_WAKEUP_CANFD10: case SDRV_WAKEUP_CANFD11: case SDRV_WAKEUP_CANFD12: case SDRV_WAKEUP_CANFD13: case SDRV_WAKEUP_CANFD14: case SDRV_WAKEUP_CANFD15: irq_num = CANFD8_CANFD_INTR_NUM + (source - SDRV_WAKEUP_CANFD8); for (uint32_t i = 0; i < 3; i++) { sdrv_ckgen_set_gate(canfd8_15_pcg[source - SDRV_WAKEUP_CANFD8][i], ckgen_mode, false); } break; #endif #ifdef APB_CANFD16_BASE case SDRV_WAKEUP_CANFD16: irq_num = CANFD16_CANFD_INTR_NUM; for (uint32_t i = 0; i < 3; i++) { sdrv_ckgen_set_gate(canfd16_pcg[0][i], ckgen_mode, false); } break; #endif #ifdef APB_CANFD17_BASE case SDRV_WAKEUP_CANFD17: case SDRV_WAKEUP_CANFD18: case SDRV_WAKEUP_CANFD19: case SDRV_WAKEUP_CANFD20: irq_num = CANFD17_CANFD_INTR_NUM + (source - SDRV_WAKEUP_CANFD17); for (uint32_t i = 0; i < 3; i++) { sdrv_ckgen_set_gate(canfd17_20_pcg[source - SDRV_WAKEUP_CANFD17][i], ckgen_mode, false); } break; #endif #ifdef APB_CANFD21_BASE case SDRV_WAKEUP_CANFD21: irq_num = CANFD21_CANFD_INTR_NUM; for (uint32_t i = 0; i < 3; i++) { sdrv_ckgen_set_gate(canfd21_pcg[0][i], ckgen_mode, false); } break; #endif #ifdef APB_CANFD22_BASE case SDRV_WAKEUP_CANFD22: irq_num = CANFD22_CANFD_INTR_NUM; for (uint32_t i = 0; i < 3; i++) { sdrv_ckgen_set_gate(canfd22_pcg[0][i], ckgen_mode, false); } break; #endif #ifdef APB_CANFD23_BASE case SDRV_WAKEUP_CANFD23: irq_num = CANFD23_CANFD_INTR_NUM; for (uint32_t i = 0; i < 3; i++) { sdrv_ckgen_set_gate(canfd23_pcg[0][i], ckgen_mode, false); } break; #endif #ifdef APB_CANFD24_BASE case SDRV_WAKEUP_CANFD24: irq_num = CANFD24_CANFD_INTR_NUM; for (uint32_t i = 0; i < 3; i++) { sdrv_ckgen_set_gate(canfd24_pcg[0][i], ckgen_mode, false); } break; #endif default: break; } if (irq_num != 0xFFFFFFFFU) { sdrv_smc_wakeup_interrupt_enable(SDRV_SMC_CORE_SF, irq_num); } } #endif /* #if CONFIG_E3 || CONFIG_D3 */ #if CONFIG_E3L || CONFIG_D3L static void sdrv_power_enable_wakeup_source_pcg(sdrv_wakeup_src_e source, sdrv_power_mode_e mode) { sdrv_ckgen_lp_mode_e ckgen_mode; uint32_t irq_num = 0xFFFFFFFFU; if (mode == SDRV_SLEEP_MODE) { ckgen_mode = CKGEN_SLP_MODE; } else if (mode == SDRV_HIBERNATE_MODE) { ckgen_mode = CKGEN_HIB_MODE; } else { return; } switch (source) { case SDRV_WAKEUP_GPIO_SF: irq_num = SDRV_SMC_ASYNC_INT_VIC1_SF_GPIO; break; case SDRV_WAKEUP_RTC1: irq_num = RTC1_RTC_WAKEUP_INTR_NUM; break; case SDRV_WAKEUP_RTC2: irq_num = RTC2_RTC_WAKEUP_INTR_NUM; break; case SDRV_WAKEUP_UART1...SDRV_WAKEUP_UART8: irq_num = UART1_INTR_NUM + (source - SDRV_WAKEUP_UART1); for (uint32_t i = 0; i < 2; i++) { sdrv_ckgen_set_gate(uarts_pcg[source - SDRV_WAKEUP_UART1][i], ckgen_mode, false); } break; #ifdef APB_UART9_BASE case SDRV_WAKEUP_UART9...SDRV_WAKEUP_UART12: irq_num = UART9_INTR_NUM + (source - SDRV_WAKEUP_UART9); for (uint32_t i = 0; i < 2; i++) { sdrv_ckgen_set_gate(uarts_pcg[source - SDRV_WAKEUP_UART1][i], ckgen_mode, false); } break; #endif #ifdef APB_CANFD16_BASE case SDRV_WAKEUP_CANFD16: irq_num = CANFD16_CANFD_INTR_NUM; for (uint32_t i = 0; i < 3; i++) { sdrv_ckgen_set_gate(canfd16_pcg[0][i], ckgen_mode, false); } break; #endif #ifdef APB_CANFD21_BASE case SDRV_WAKEUP_CANFD21: irq_num = CANFD21_CANFD_INTR_NUM; for (uint32_t i = 0; i < 3; i++) { sdrv_ckgen_set_gate(canfd21_pcg[0][i], ckgen_mode, false); } break; #endif #ifdef APB_CANFD3_BASE case SDRV_WAKEUP_CANFD3: case SDRV_WAKEUP_CANFD4: irq_num = CANFD3_CANFD_INTR_NUM + (source - SDRV_WAKEUP_CANFD3); for (uint32_t i = 0; i < 3; i++) { sdrv_ckgen_set_gate(canfd3_4_pcg[source - SDRV_WAKEUP_CANFD3][i], ckgen_mode, false); } break; #endif #ifdef APB_CANFD5_BASE case SDRV_WAKEUP_CANFD5: case SDRV_WAKEUP_CANFD6: irq_num = CANFD5_CANFD_INTR_NUM + (source - SDRV_WAKEUP_CANFD5); for (uint32_t i = 0; i < 3; i++) { sdrv_ckgen_set_gate(canfd5_6_pcg[source - SDRV_WAKEUP_CANFD5][i], ckgen_mode, false); } break; #endif #ifdef APB_CANFD7_BASE case SDRV_WAKEUP_CANFD7: irq_num = CANFD7_CANFD_INTR_NUM; for (uint32_t i = 0; i < 3; i++) { sdrv_ckgen_set_gate(canfd7_pcg[0][i], ckgen_mode, false); } break; #endif #ifdef APB_CANFD23_BASE case SDRV_WAKEUP_CANFD23: irq_num = CANFD23_CANFD_INTR_NUM; for (uint32_t i = 0; i < 3; i++) { sdrv_ckgen_set_gate(canfd23_pcg[0][i], ckgen_mode, false); } break; #endif default: break; } if (irq_num != 0xFFFFFFFFU) { sdrv_smc_wakeup_interrupt_enable(SDRV_SMC_CORE_SF, irq_num); } } #endif /* #if CONFIG_E3L || CONFIG_D3L */ static void sdrv_power_pll_power_down_mask(uint32_t pd_mask, sdrv_power_mode_e mode) { sdrv_ckgen_lp_mode_e ckgen_mode; sdrv_ckgen_node_t ckgen_node; ckgen_node.type = CKGEN_PLL_CG_TYPE; if (mode == SDRV_SLEEP_MODE) { ckgen_mode = CKGEN_SLP_MODE; } else if (mode == SDRV_HIBERNATE_MODE) { ckgen_mode = CKGEN_HIB_MODE; } else { return; } ckgen_node.base = APB_CKGEN_SF_BASE; ckgen_node.id = 0; sdrv_ckgen_set_gate(&ckgen_node, ckgen_mode, !(pd_mask & SDRV_PLL1_PD_MASK)); sdrv_ckgen_set_pll_power(&ckgen_node, ckgen_mode, !(pd_mask & SDRV_PLL1_PD_MASK)); ckgen_node.id = 1; sdrv_ckgen_set_gate(&ckgen_node, ckgen_mode, !(pd_mask & SDRV_PLL2_PD_MASK)); sdrv_ckgen_set_pll_power(&ckgen_node, ckgen_mode, !(pd_mask & SDRV_PLL2_PD_MASK)); ckgen_node.id = 2; sdrv_ckgen_set_gate(&ckgen_node, ckgen_mode, !(pd_mask & SDRV_PLL3_PD_MASK)); sdrv_ckgen_set_pll_power(&ckgen_node, ckgen_mode, !(pd_mask & SDRV_PLL3_PD_MASK)); #ifdef APB_CKGEN_AP_BASE ckgen_node.base = APB_CKGEN_AP_BASE; ckgen_node.id = 0; sdrv_ckgen_set_gate(&ckgen_node, ckgen_mode, !(pd_mask & SDRV_PLL4_PD_MASK)); sdrv_ckgen_set_pll_power(&ckgen_node, ckgen_mode, !(pd_mask & SDRV_PLL4_PD_MASK)); ckgen_node.id = 1; sdrv_ckgen_set_gate(&ckgen_node, ckgen_mode, !(pd_mask & SDRV_PLL5_PD_MASK)); sdrv_ckgen_set_pll_power(&ckgen_node, ckgen_mode, !(pd_mask & SDRV_PLL5_PD_MASK)); ckgen_node.id = 2; sdrv_ckgen_set_gate(&ckgen_node, ckgen_mode, !(pd_mask & SDRV_PLL_LVDS_PD_MASK)); sdrv_ckgen_set_pll_power(&ckgen_node, ckgen_mode, !(pd_mask & SDRV_PLL_LVDS_PD_MASK)); #endif } static void sdrv_power_xtal_24m_config(bool enable, sdrv_power_mode_e mode) { sdrv_ckgen_lp_mode_e ckgen_mode; sdrv_ckgen_node_t ckgen_node; ckgen_node.type = CKGEN_XTAL_CG_TYPE; ckgen_node.id = 0; if (mode == SDRV_SLEEP_MODE) { ckgen_mode = CKGEN_SLP_MODE; } else if (mode == SDRV_HIBERNATE_MODE) { ckgen_mode = CKGEN_HIB_MODE; } else { return; } ckgen_node.base = APB_CKGEN_SF_BASE; sdrv_ckgen_set_gate(&ckgen_node, ckgen_mode, !enable); #ifdef APB_CKGEN_AP_BASE ckgen_node.base = APB_CKGEN_AP_BASE; sdrv_ckgen_set_gate(&ckgen_node, ckgen_mode, !enable); #endif } static void sdrv_power_rstsig_insert(sdrv_power_ctrl_t *power_ctrl, sdrv_rstgen_sig_t *rstsig, sdrv_power_mode_e mode, uint8_t rst_val) { sdrv_rstgen_sig_t **rstsig_head; if (rst_val) { return; } if (mode == SDRV_SLEEP_MODE) { rstsig_head = &power_ctrl->sleep_rstsig[0]; } else if (mode == SDRV_HIBERNATE_MODE) { rstsig_head = &power_ctrl->hib_rstsig[0]; } else { return; } for (uint32_t i = 0; i < SDRV_POWER_RSTSIG_NUM; i++, rstsig_head++) { if (*rstsig_head == NULL) { *rstsig_head = rstsig; return; } } } static void sdrv_power_rstsig_handler(sdrv_power_ctrl_t *power_ctrl, sdrv_power_mode_e mode, uint8_t when) { sdrv_rstgen_sig_t **rstsig_head; if (mode == SDRV_SLEEP_MODE) { rstsig_head = &power_ctrl->sleep_rstsig[0]; } else if (mode == SDRV_HIBERNATE_MODE) { rstsig_head = &power_ctrl->hib_rstsig[0]; } else { return; } for (uint32_t i = 0; i < SDRV_POWER_RSTSIG_NUM; i++, rstsig_head++) { sdrv_rstgen_sig_t *curr_sig = *rstsig_head; if (curr_sig) { if (!when && curr_sig->pre_handler) { curr_sig->pre_handler(curr_sig->id); } else if (when && curr_sig->post_handler) { curr_sig->post_handler(curr_sig->id); } } } } #if CONFIG_E3 || CONFIG_D3 static void sdrv_power_saf_module_reset_config(uint32_t reset_mask, sdrv_power_mode_e mode) { enum reset_lowpower_mode rstgen_mode; if (mode == SDRV_SLEEP_MODE) { rstgen_mode = RESET_LP_SLEEP; } else if (mode == SDRV_HIBERNATE_MODE) { rstgen_mode = RESET_LP_HIB; } else { return; } #ifdef APB_CANFD1_BASE sdrv_rstgen_lowpower_set(&rstsig_canfd1, rstgen_mode, !!(reset_mask & SDRV_SF_MODULE_CANFD1_MASK)); sdrv_rstgen_lowpower_set(&rstsig_canfd2, rstgen_mode, !!(reset_mask & SDRV_SF_MODULE_CANFD2_MASK)); #endif #ifdef APB_CANFD3_BASE sdrv_rstgen_lowpower_set(&rstsig_canfd3_4, rstgen_mode, !!(reset_mask & SDRV_SF_MODULE_CANFD3_4_MASK)); #endif #if defined(APB_CANFD5_BASE) || defined(APB_CANFD7_BASE) || defined(APB_CANFD8_BASE) sdrv_rstgen_lowpower_set(&rstsig_canfd5_8, rstgen_mode, !!(reset_mask & SDRV_SF_MODULE_CANFD5_8_MASK)); #endif #if defined(APB_CANFD8_BASE) || defined(APB_CANFD16_BASE) sdrv_rstgen_lowpower_set(&rstsig_canfd9_16, rstgen_mode, !!(reset_mask & SDRV_SF_MODULE_CANFD9_16_MASK)); #endif #if defined(APB_CANFD17_BASE) || defined(APB_CANFD21_BASE) || defined(APB_CANFD22_BASE) || defined(APB_CANFD23_BASE) sdrv_rstgen_lowpower_set(&rstsig_canfd17_24, rstgen_mode, !!(reset_mask & SDRV_SF_MODULE_CANFD17_24_MASK)); #endif #ifdef XSPI1_BASE sdrv_rstgen_lowpower_set(&rstsig_xspi1a, rstgen_mode, !!(reset_mask & SDRV_SF_MODULE_XSPI1A_MASK)); sdrv_rstgen_lowpower_set(&rstsig_xspi1b, rstgen_mode, !!(reset_mask & SDRV_SF_MODULE_XSPI1B_MASK)); sdrv_power_rstsig_insert(&g_power_ctrl, &rstsig_xspi1a, mode, !!(reset_mask & SDRV_SF_MODULE_XSPI1A_MASK)); sdrv_power_rstsig_insert(&g_power_ctrl, &rstsig_xspi1b, mode, !!(reset_mask & SDRV_SF_MODULE_XSPI1B_MASK)); #endif #ifdef XSPI2_BASE sdrv_rstgen_lowpower_set(&rstsig_xspi2a, rstgen_mode, !!(reset_mask & SDRV_SF_MODULE_XSPI2A_MASK)); sdrv_rstgen_lowpower_set(&rstsig_xspi2b, rstgen_mode, !!(reset_mask & SDRV_SF_MODULE_XSPI2B_MASK)); sdrv_power_rstsig_insert(&g_power_ctrl, &rstsig_xspi2a, mode, !!(reset_mask & SDRV_SF_MODULE_XSPI2A_MASK)); sdrv_power_rstsig_insert(&g_power_ctrl, &rstsig_xspi2b, mode, !!(reset_mask & SDRV_SF_MODULE_XSPI2B_MASK)); #endif sdrv_rstgen_lowpower_set(&rstsig_dma_rst0, rstgen_mode, !!(reset_mask & SDRV_SF_MODULE_DMA_MASK)); sdrv_rstgen_lowpower_set(&rstsig_dma_rst1, rstgen_mode, !!(reset_mask & SDRV_SF_MODULE_DMA_MASK)); #ifdef APB_GAMA1_BASE sdrv_rstgen_lowpower_set(&rstsig_gama1, rstgen_mode, !!(reset_mask & SDRV_SF_MODULE_GAMA1_MASK)); sdrv_rstgen_lowpower_set(&rstsig_ahb_syncup_gama1, rstgen_mode, !!(reset_mask & SDRV_SF_MODULE_GAMA1_MASK)); sdrv_rstgen_lowpower_set(&rstsig_gama2, rstgen_mode, !!(reset_mask & SDRV_SF_MODULE_GAMA2_MASK)); sdrv_rstgen_lowpower_set(&rstsig_ahb_syncup_gama2, rstgen_mode, !!(reset_mask & SDRV_SF_MODULE_GAMA2_MASK)); #endif #ifdef APB_ENET1_BASE sdrv_rstgen_lowpower_set(&rstsig_enet1, rstgen_mode, !!(reset_mask & SDRV_SF_MODULE_ENET1_MASK)); #endif #ifdef APB_ENET2_BASE sdrv_rstgen_lowpower_set(&rstsig_enet2, rstgen_mode, !!(reset_mask & SDRV_SF_MODULE_ENET2_MASK)); #endif sdrv_rstgen_lowpower_set(&rstsig_vic1, rstgen_mode, !!(reset_mask & SDRV_SF_MODULE_VIC1_MASK)); #ifdef VIC2PORTA_BASE sdrv_rstgen_lowpower_set(&rstsig_vic2_porta, rstgen_mode, !!(reset_mask & SDRV_SF_MODULE_VIC2A_MASK)); #endif #ifdef VIC2PORTB_BASE sdrv_rstgen_lowpower_set(&rstsig_vic2_portb, rstgen_mode, !!(reset_mask & SDRV_SF_MODULE_VIC2B_MASK)); #endif #ifdef VIC3PORTA_BASE sdrv_rstgen_lowpower_set(&rstsig_vic3_porta, rstgen_mode, !!(reset_mask & SDRV_SF_MODULE_VIC3A_MASK)); #endif #ifdef VIC3PORTB_BASE sdrv_rstgen_lowpower_set(&rstsig_vic3_portb, rstgen_mode, !!(reset_mask & SDRV_SF_MODULE_VIC3B_MASK)); #endif sdrv_rstgen_lowpower_set(&rstsig_xspi_slv, rstgen_mode, !!(reset_mask & SDRV_SF_MODULE_XSPI_SLV_MASK)); sdrv_rstgen_lowpower_set(&rstsig_mb, rstgen_mode, !!(reset_mask & SDRV_SF_MODULE_MB_MASK)); sdrv_rstgen_lowpower_set(&rstsig_xtrg, rstgen_mode, !!(reset_mask & SDRV_SF_MODULE_XTRG_MASK)); } static void sdrv_power_core_power_gate_config(uint32_t pd_mask, sdrv_smc_mode_e mode) { if (pd_mask & SDRV_SF_PD_MASK) { sdrv_smc_power_switch_config(SDRV_SMC_POWER_SWITCH_SF, mode, false); sdrv_smc_ram_lowpower_config(SDRV_SMC_RAM_SF, mode, SDRV_SMC_CHIP_ENABLE); /* retention mode not support */ } else { /* this case must reset core */ sdrv_smc_power_switch_config(SDRV_SMC_POWER_SWITCH_SF, mode, true); sdrv_smc_ram_lowpower_config(SDRV_SMC_RAM_SF, mode, SDRV_SMC_POWER_DOWN); /* core pd, ram must pd */ sdrv_rstgen_lowpower_set(&rstsig_cr5_saf, RESET_LP_HIB, false); } if (pd_mask & SDRV_SP_PD_MASK) { sdrv_smc_power_switch_config(SDRV_SMC_POWER_SWITCH_SP, mode, false); sdrv_smc_ram_lowpower_config(SDRV_SMC_RAM_SP, mode, SDRV_SMC_CHIP_ENABLE); } else { sdrv_smc_power_switch_config(SDRV_SMC_POWER_SWITCH_SP, mode, true); sdrv_smc_ram_lowpower_config(SDRV_SMC_RAM_SP, mode, SDRV_SMC_POWER_DOWN); #if defined(CORE_SP0) || defined(CORE_SP1) sdrv_rstgen_lowpower_set(&rstsig_cr5_sp0, RESET_LP_HIB, false); sdrv_rstgen_lowpower_set(&rstsig_cr5_sp1, RESET_LP_HIB, false); #endif } if (pd_mask & SDRV_SX_PD_MASK) { sdrv_smc_power_switch_config(SDRV_SMC_POWER_SWITCH_SX, mode, false); sdrv_smc_ram_lowpower_config(SDRV_SMC_RAM_SX, mode, SDRV_SMC_CHIP_ENABLE); } else { sdrv_smc_power_switch_config(SDRV_SMC_POWER_SWITCH_SX, mode, true); sdrv_smc_ram_lowpower_config(SDRV_SMC_RAM_SX, mode, SDRV_SMC_POWER_DOWN); #if defined(CORE_SX0) || defined(CORE_SX1) sdrv_rstgen_lowpower_set(&rstsig_cr5_sx0, RESET_LP_HIB, false); sdrv_rstgen_lowpower_set(&rstsig_cr5_sx1, RESET_LP_HIB, false); #endif } if (pd_mask & SDRV_GAMA1_PD_MASK) { sdrv_smc_power_switch_config(SDRV_SMC_POWER_SWITCH_GAMA1, mode, false); sdrv_smc_ram_lowpower_config(SDRV_SMC_RAM_GAMA1, mode, SDRV_SMC_CHIP_ENABLE); } else { sdrv_smc_power_switch_config(SDRV_SMC_POWER_SWITCH_GAMA1, mode, true); sdrv_smc_ram_lowpower_config(SDRV_SMC_RAM_GAMA1, mode, SDRV_SMC_POWER_DOWN); } if (pd_mask & SDRV_AP_DISP_PD_MASK) { sdrv_smc_power_switch_config(SDRV_SMC_POWER_SWITCH_AP_DISP, mode, false); sdrv_smc_ram_lowpower_config(SDRV_SMC_RAM_AP, mode, SDRV_SMC_CHIP_ENABLE); sdrv_smc_ram_lowpower_config(SDRV_SMC_RAM_DISP, mode, SDRV_SMC_CHIP_ENABLE); } else { sdrv_smc_power_switch_config(SDRV_SMC_POWER_SWITCH_AP_DISP, mode, true); sdrv_smc_ram_lowpower_config(SDRV_SMC_RAM_AP, mode, SDRV_SMC_POWER_DOWN); sdrv_smc_ram_lowpower_config(SDRV_SMC_RAM_DISP, mode, SDRV_SMC_POWER_DOWN); } if (pd_mask & (SDRV_SF_PD_MASK | SDRV_SP_PD_MASK | SDRV_SX_PD_MASK | SDRV_GAMA1_PD_MASK)) { sdrv_smc_ram_lowpower_config(SDRV_SMC_RAM_SF_MISC, mode, SDRV_SMC_CHIP_ENABLE); } else { sdrv_smc_ram_lowpower_config(SDRV_SMC_RAM_SF_MISC, mode, SDRV_SMC_POWER_DOWN); } } static uint32_t sdrv_power_get_core_power_switch_runmode_config(void) { uint32_t ret = 0; if (sdrv_smc_software_power_switch_gate_status(SDRV_SMC_POWER_SWITCH_SF)) { ret |= SDRV_SF_PD_MASK; } if (sdrv_smc_software_power_switch_gate_status(SDRV_SMC_POWER_SWITCH_SP)) { ret |= SDRV_SP_PD_MASK; } if (sdrv_smc_software_power_switch_gate_status(SDRV_SMC_POWER_SWITCH_SX)) { ret |= SDRV_SX_PD_MASK; } if (sdrv_smc_software_power_switch_gate_status(SDRV_SMC_POWER_SWITCH_GAMA1)) { ret |= SDRV_GAMA1_PD_MASK; } if (sdrv_smc_software_power_switch_gate_status(SDRV_SMC_POWER_SWITCH_AP_DISP)) { ret |= SDRV_AP_DISP_PD_MASK; } return ret; } static status_t sdrv_power_software_apss_off(void) { status_t ret = SDRV_STATUS_OK; /* ap mission[1] and module[10:3] should assert in hibernate */ if (sdrv_ckgen_bus_set_rate(CLK_NODE(g_ckgen_bus_ap_bus), CLK_24M_RATE, CKGEN_BUS_DIV_4_2_1)) { return SDRV_POWER_CLOCK_SET_FAILED; } sdrv_smc_trigger_software_handshake(SDRV_SMC_HK_AP_CKGEN, SDRV_SMC_SWM_HIB); sdrv_smc_trigger_software_handshake(SDRV_SMC_HK_AP_RSTGEN, SDRV_SMC_SWM_HIB); ret |= sdrv_smc_trigger_software_ram_lowpower(SDRV_SMC_RAM_DISP, SDRV_SMC_POWER_DOWN); ret |= sdrv_smc_trigger_software_ram_lowpower(SDRV_SMC_RAM_AP, SDRV_SMC_POWER_DOWN); ret |= sdrv_smc_trigger_software_power_switch(SDRV_SMC_POWER_SWITCH_AP_DISP, true); sdrv_smc_ap_domain_handshake(false); /* wait ap_ss not ready */ if (!sdrv_power_wait(APB_RSTGEN_SF_BASE + 0x204U, 31, 0, SDRV_POWER_POLL_COUNT)) { return SDRV_POWER_AP_STATUS_ERROR; } return ret; } static status_t sdrv_power_software_apss_on(void) { status_t ret = SDRV_STATUS_OK; ret |= sdrv_smc_trigger_software_ram_lowpower(SDRV_SMC_RAM_DISP, SDRV_SMC_CHIP_ENABLE); ret |= sdrv_smc_trigger_software_ram_lowpower(SDRV_SMC_RAM_AP, SDRV_SMC_CHIP_ENABLE); ret |= sdrv_smc_trigger_software_power_switch(SDRV_SMC_POWER_SWITCH_AP_DISP, false); sdrv_smc_trigger_software_handshake(SDRV_SMC_HK_AP_RSTGEN, SDRV_SMC_SWM_RUN); sdrv_smc_trigger_software_handshake(SDRV_SMC_HK_AP_CKGEN, SDRV_SMC_SWM_RUN); /* wait ap_ss ready */ if (!sdrv_power_wait(APB_RSTGEN_SF_BASE + 0x204U, 31, 1, SDRV_POWER_POLL_COUNT)) { return SDRV_POWER_AP_STATUS_ERROR; } return ret; } static status_t sdrv_power_core_power_switch_software_set(sdrv_smc_power_switch_e power_switch, bool set, bool gate) { status_t ret = SDRV_STATUS_OK; if (set) { if (gate) { switch (power_switch) { #if defined(CORE_SP0) || defined(CORE_SP1) case SDRV_SMC_POWER_SWITCH_SP: sdrv_ckgen_ip_clock_enable(g_ckgen_cr5_sp, CKGEN_RUN_MODE, false); sdrv_rstgen_assert(&rstsig_cr5_sp0); sdrv_rstgen_assert(&rstsig_cr5_sp1); sdrv_smc_trigger_software_ram_lowpower(SDRV_SMC_RAM_SP, SDRV_SMC_POWER_DOWN); break; #endif #if defined(CORE_SX0) || defined(CORE_SX1) case SDRV_SMC_POWER_SWITCH_SX: sdrv_ckgen_ip_clock_enable(g_ckgen_cr5_sx, CKGEN_RUN_MODE, false); sdrv_rstgen_assert(&rstsig_cr5_sx0); sdrv_rstgen_assert(&rstsig_cr5_sx1); sdrv_smc_trigger_software_ram_lowpower(SDRV_SMC_RAM_SX, SDRV_SMC_POWER_DOWN); break; #endif case SDRV_SMC_POWER_SWITCH_GAMA1: sdrv_ckgen_ip_clock_enable(g_ckgen_gama1, CKGEN_RUN_MODE, false); #ifdef APB_GAMA1_BASE sdrv_rstgen_assert(&rstsig_gama1); #endif sdrv_rstgen_assert(&rstsig_saf_mission6); sdrv_smc_trigger_software_ram_lowpower(SDRV_SMC_RAM_GAMA1, SDRV_SMC_POWER_DOWN); break; case SDRV_SMC_POWER_SWITCH_AP_DISP: return sdrv_power_software_apss_off(); break; default: break; } sdrv_smc_trigger_software_power_switch(power_switch, true); } else { switch (power_switch) { #if defined(CORE_SP0) || defined(CORE_SP1) case SDRV_SMC_POWER_SWITCH_SP: sdrv_ckgen_ip_clock_enable(g_ckgen_cr5_sp, CKGEN_RUN_MODE, true); sdrv_smc_trigger_software_ram_lowpower(SDRV_SMC_RAM_SP, SDRV_SMC_CHIP_ENABLE); sdrv_smc_trigger_software_power_switch(power_switch, false); break; #endif #if defined(CORE_SX0) || defined(CORE_SX1) case SDRV_SMC_POWER_SWITCH_SX: sdrv_ckgen_ip_clock_enable(g_ckgen_cr5_sx, CKGEN_RUN_MODE, true); sdrv_smc_trigger_software_ram_lowpower(SDRV_SMC_RAM_SX, SDRV_SMC_CHIP_ENABLE); sdrv_smc_trigger_software_power_switch(power_switch, false); break; #endif case SDRV_SMC_POWER_SWITCH_GAMA1: sdrv_ckgen_ip_clock_enable(g_ckgen_gama1, CKGEN_RUN_MODE, true); sdrv_smc_trigger_software_ram_lowpower(SDRV_SMC_RAM_GAMA1, SDRV_SMC_CHIP_ENABLE); sdrv_smc_trigger_software_power_switch(power_switch, false); sdrv_rstgen_deassert(&rstsig_saf_mission6); break; default: break; } } } return ret; } static status_t sdrv_power_core_power_switch_before_hib(uint32_t pd_mask) { status_t ret = SDRV_STATUS_OK; ret |= sdrv_power_core_power_switch_software_set(SDRV_SMC_POWER_SWITCH_SX, !(pd_mask & SDRV_SX_PD_MASK), true); ret |= sdrv_power_core_power_switch_software_set(SDRV_SMC_POWER_SWITCH_SP, !(pd_mask & SDRV_SP_PD_MASK), true); ret |= sdrv_power_core_power_switch_software_set(SDRV_SMC_POWER_SWITCH_GAMA1, !(pd_mask & SDRV_GAMA1_PD_MASK), true); ret |= sdrv_power_core_power_switch_software_set(SDRV_SMC_POWER_SWITCH_AP_DISP, !(pd_mask & SDRV_AP_DISP_PD_MASK), true); return ret; } static status_t sdrv_power_core_power_switch_after_hib(uint32_t pd_mask) { status_t ret = SDRV_STATUS_OK; ret |= sdrv_power_core_power_switch_software_set(SDRV_SMC_POWER_SWITCH_GAMA1, !(pd_mask & SDRV_GAMA1_PD_MASK), false); ret |= sdrv_power_core_power_switch_software_set(SDRV_SMC_POWER_SWITCH_SP, !(pd_mask & SDRV_SP_PD_MASK), false); ret |= sdrv_power_core_power_switch_software_set(SDRV_SMC_POWER_SWITCH_SX, !(pd_mask & SDRV_SX_PD_MASK), false); return ret; } #endif /* #if CONFIG_E3 || CONFIG_D3 */ #if CONFIG_E3L || CONFIG_D3L static void sdrv_power_saf_module_reset_config(uint32_t reset_mask, sdrv_power_mode_e mode) { enum reset_lowpower_mode rstgen_mode; if (mode == SDRV_SLEEP_MODE) { rstgen_mode = RESET_LP_SLEEP; } else if (mode == SDRV_HIBERNATE_MODE) { rstgen_mode = RESET_LP_HIB; } else { return; } sdrv_rstgen_lowpower_set(&rstsig_canfd16, rstgen_mode, !!(reset_mask & SDRV_SF_MODULE_CANFD16_MASK)); sdrv_rstgen_lowpower_set(&rstsig_canfd21, rstgen_mode, !!(reset_mask & SDRV_SF_MODULE_CANFD21_MASK)); sdrv_rstgen_lowpower_set(&rstsig_canfd3, rstgen_mode, !!(reset_mask & SDRV_SF_MODULE_CANFD3_MASK)); sdrv_rstgen_lowpower_set(&rstsig_canfd4, rstgen_mode, !!(reset_mask & SDRV_SF_MODULE_CANFD4_MASK)); sdrv_rstgen_lowpower_set(&rstsig_canfd5, rstgen_mode, !!(reset_mask & SDRV_SF_MODULE_CANFD5_MASK)); sdrv_rstgen_lowpower_set(&rstsig_canfd6, rstgen_mode, !!(reset_mask & SDRV_SF_MODULE_CANFD6_MASK)); sdrv_rstgen_lowpower_set(&rstsig_canfd7, rstgen_mode, !!(reset_mask & SDRV_SF_MODULE_CANFD7_MASK)); sdrv_rstgen_lowpower_set(&rstsig_canfd23, rstgen_mode, !!(reset_mask & SDRV_SF_MODULE_CANFD23_MASK)); sdrv_rstgen_lowpower_set(&rstsig_xspi1a, rstgen_mode, !!(reset_mask & SDRV_SF_MODULE_XSPI1A_MASK)); sdrv_rstgen_lowpower_set(&rstsig_xspi1b, rstgen_mode, !!(reset_mask & SDRV_SF_MODULE_XSPI1B_MASK)); sdrv_power_rstsig_insert(&g_power_ctrl, &rstsig_xspi1a, mode, !!(reset_mask & SDRV_SF_MODULE_XSPI1A_MASK)); sdrv_power_rstsig_insert(&g_power_ctrl, &rstsig_xspi1b, mode, !!(reset_mask & SDRV_SF_MODULE_XSPI1B_MASK)); sdrv_rstgen_lowpower_set(&rstsig_dma_rst0, rstgen_mode, !!(reset_mask & SDRV_SF_MODULE_DMA_RST0_MASK)); sdrv_rstgen_lowpower_set(&rstsig_dma_rst1, rstgen_mode, !!(reset_mask & SDRV_SF_MODULE_DMA_RST1_MASK)); sdrv_rstgen_lowpower_set(&rstsig_enet1, rstgen_mode, !!(reset_mask & SDRV_SF_MODULE_ENET1_MASK)); sdrv_rstgen_lowpower_set(&rstsig_vic1, rstgen_mode, !!(reset_mask & SDRV_SF_MODULE_VIC1_MASK)); sdrv_rstgen_lowpower_set(&rstsig_xspi_slv, rstgen_mode, !!(reset_mask & SDRV_SF_MODULE_XSPI_SLV_MASK)); sdrv_rstgen_lowpower_set(&rstsig_xtrg, rstgen_mode, !!(reset_mask & SDRV_SF_MODULE_XTRG_MASK)); sdrv_rstgen_lowpower_set(&rstsig_saci2, rstgen_mode, !!(reset_mask & SDRV_SF_MODULE_SACI2_MASK)); sdrv_rstgen_lowpower_set(&rstsig_sehc1, rstgen_mode, !!(reset_mask & SDRV_SF_MODULE_SEHC1_MASK)); sdrv_rstgen_lowpower_set(&rstsig_usb, rstgen_mode, !!(reset_mask & SDRV_SF_MODULE_USB_MASK)); sdrv_rstgen_lowpower_set(&rstsig_seip, rstgen_mode, !!(reset_mask & SDRV_SF_MODULE_SEIP_MASK)); sdrv_rstgen_lowpower_set(&rstsig_cslite, rstgen_mode, !!(reset_mask & SDRV_SF_MODULE_CSLITE_MASK)); } static void sdrv_power_core_power_gate_config(uint32_t pd_mask, sdrv_smc_mode_e mode) { if (pd_mask & SDRV_SF_PD_MASK) { sdrv_smc_power_switch_config(SDRV_SMC_POWER_SWITCH_SF, mode, false); if (IS_1P0) { sdrv_smc_ram_lowpower_config(SDRV_SMC_RAM_SF, mode, SDRV_SMC_CHIP_ENABLE); } else { sdrv_smc_ram_lowpower_config(SDRV_SMC_RAM_SF, mode, SDRV_SMC_RETENTION_2); } } else { /* this case must reset core */ sdrv_smc_power_switch_config(SDRV_SMC_POWER_SWITCH_SF, mode, true); sdrv_smc_ram_lowpower_config(SDRV_SMC_RAM_SF, mode, SDRV_SMC_POWER_DOWN); /* core pd, ram must pd */ sdrv_rstgen_lowpower_set(&rstsig_cr5_saf, RESET_LP_HIB, false); } if (pd_mask & SDRV_SF_BOOT_PD_MASK) { sdrv_smc_power_switch_config(SDRV_SMC_POWER_SWITCH_SF_BOOT, mode, false); if (IS_1P0) { sdrv_smc_ram_lowpower_config(SDRV_SMC_RAM_SF_BOOT, mode, SDRV_SMC_CHIP_ENABLE); } else { sdrv_smc_ram_lowpower_config(SDRV_SMC_RAM_SF_BOOT, mode, SDRV_SMC_RETENTION_2); } } else { /* this case must reset core */ sdrv_smc_power_switch_config(SDRV_SMC_POWER_SWITCH_SF_BOOT, mode, true); sdrv_smc_ram_lowpower_config(SDRV_SMC_RAM_SF_BOOT, mode, SDRV_SMC_POWER_DOWN); /* core pd, ram must pd */ } if ((pd_mask & SDRV_AP_MIX_PD_MASK) || (IS_1P0)) { sdrv_smc_power_switch_config(SDRV_SMC_POWER_SWITCH_AP_MIX, mode, false); if (IS_1P0) { sdrv_smc_ram_lowpower_config(SDRV_SMC_RAM_AP_MIX, mode, SDRV_SMC_CHIP_ENABLE); } else { sdrv_smc_ram_lowpower_config(SDRV_SMC_RAM_AP_MIX, mode, SDRV_SMC_RETENTION_2); } } else { /* this case must reset core */ sdrv_smc_power_switch_config(SDRV_SMC_POWER_SWITCH_AP_MIX, mode, true); sdrv_smc_ram_lowpower_config(SDRV_SMC_RAM_AP_MIX, mode, SDRV_SMC_POWER_DOWN); /* core pd, ram must pd */ } } static uint32_t sdrv_power_get_core_power_switch_runmode_config(void) { uint32_t ret = 0; if (sdrv_smc_software_power_switch_gate_status(SDRV_SMC_POWER_SWITCH_SF)) { ret |= SDRV_SF_PD_MASK; } if (sdrv_smc_software_power_switch_gate_status(SDRV_SMC_POWER_SWITCH_SF_BOOT)) { ret |= SDRV_SF_BOOT_PD_MASK; } if (sdrv_smc_software_power_switch_gate_status(SDRV_SMC_POWER_SWITCH_AP_MIX)) { ret |= SDRV_AP_MIX_PD_MASK; } return ret; } static status_t sdrv_power_software_apmix_off(void) { status_t ret; ret = sdrv_rstgen_assert(&rstsig_mission5); if (ret != SDRV_STATUS_OK) { return ret; } ret = sdrv_smc_trigger_software_ram_lowpower(SDRV_SMC_RAM_AP_MIX, SDRV_SMC_POWER_DOWN); ret = sdrv_smc_trigger_software_power_switch(SDRV_SMC_POWER_SWITCH_AP_MIX, true); for (uint32_t i = 0; i < ARRAY_SIZE(ap_mix_cgs); i++) { ret = sdrv_ckgen_set_gate(ap_mix_cgs[i], CKGEN_HIB_MODE, true); ret = sdrv_ckgen_set_gate(ap_mix_cgs[i], CKGEN_RUN_MODE, true); } /* If ap_mix software power down, cgs below must set on in hib */ sdrv_ckgen_set_gate(CLK_NODE(g_ckgen_gating_fab_sf_hsmclk), CKGEN_HIB_MODE, false); sdrv_ckgen_set_gate(CLK_NODE(g_ckgen_gating_saci2_tx_perclk), CKGEN_HIB_MODE, false); sdrv_ckgen_set_gate(CLK_NODE(g_ckgen_gating_saci2_rx_perclk), CKGEN_HIB_MODE, false); sdrv_ckgen_set_gate(CLK_NODE(g_ckgen_gating_saci2_pdm_perclk), CKGEN_HIB_MODE, false); return ret; } static status_t sdrv_power_software_apmix_on(void) { status_t ret; ret = sdrv_smc_trigger_software_ram_lowpower(SDRV_SMC_RAM_AP_MIX, SDRV_SMC_CHIP_ENABLE); ret = sdrv_smc_trigger_software_power_switch(SDRV_SMC_POWER_SWITCH_AP_MIX, false); ret = sdrv_rstgen_deassert(&rstsig_mission5); if (ret != SDRV_STATUS_OK) { return ret; } for (uint32_t i = 0; i < ARRAY_SIZE(ap_mix_cgs); i++) { ret = sdrv_ckgen_set_gate(ap_mix_cgs[i], CKGEN_RUN_MODE, false); } return ret; } static status_t sdrv_power_core_power_switch_software_set(sdrv_smc_power_switch_e power_switch, bool set, bool gate) { status_t ret = SDRV_STATUS_OK; if ((power_switch == SDRV_SMC_POWER_SWITCH_AP_MIX) && set) { if (gate) { ret = sdrv_power_software_apmix_off(); } else { ret = sdrv_power_software_apmix_on(); } } return ret; } static status_t sdrv_power_core_power_switch_before_hib(uint32_t pd_mask) { status_t ret = SDRV_STATUS_OK; ret |= sdrv_power_core_power_switch_software_set(SDRV_SMC_POWER_SWITCH_AP_MIX, !(pd_mask & SDRV_AP_MIX_PD_MASK), true); ret |= sdrv_power_core_power_switch_software_set(SDRV_SMC_POWER_SWITCH_SF_BOOT, !(pd_mask & SDRV_SF_BOOT_PD_MASK), true); ret |= sdrv_power_core_power_switch_software_set(SDRV_SMC_POWER_SWITCH_SF, !(pd_mask & SDRV_SF_PD_MASK), true); return ret; } static status_t sdrv_power_core_power_switch_after_hib(uint32_t pd_mask) { status_t ret = SDRV_STATUS_OK; ret |= sdrv_power_core_power_switch_software_set(SDRV_SMC_POWER_SWITCH_AP_MIX, !(pd_mask & SDRV_AP_MIX_PD_MASK), false); ret |= sdrv_power_core_power_switch_software_set(SDRV_SMC_POWER_SWITCH_SF_BOOT, !(pd_mask & SDRV_SF_BOOT_PD_MASK), false); ret |= sdrv_power_core_power_switch_software_set(SDRV_SMC_POWER_SWITCH_SF, !(pd_mask & SDRV_SF_PD_MASK), false); return ret; } #endif /* #if CONFIG_E3L || CONFIG_D3L */ #ifdef APB_RSTGEN_AP_BASE static void sdrv_power_ap_module_reset_config(uint32_t reset_mask, sdrv_power_mode_e mode) { enum reset_lowpower_mode rstgen_mode; if (mode == SDRV_SLEEP_MODE) { rstgen_mode = RESET_LP_SLEEP; } else if (mode == SDRV_HIBERNATE_MODE) { rstgen_mode = RESET_LP_HIB; } else { return; } #ifdef APB_CSI_BASE sdrv_rstgen_lowpower_set(&rstsig_csi, rstgen_mode, !!(reset_mask & SDRV_AP_MODULE_CSI_MASK)); #endif #ifdef APB_DC_BASE sdrv_rstgen_lowpower_set(&rstsig_dc, rstgen_mode, !!(reset_mask & SDRV_AP_MODULE_DC_MASK)); #endif #ifdef APB_G2D_BASE sdrv_rstgen_lowpower_set(&rstsig_g2d, rstgen_mode, !!(reset_mask & SDRV_AP_MODULE_G2D_MASK)); #endif #ifdef APB_SDRAMC_BASE sdrv_rstgen_lowpower_set(&rstsig_sdramc, rstgen_mode, !!(reset_mask & SDRV_AP_MODULE_SDRAMC_MASK)); #endif #ifdef APB_SACI1_BASE sdrv_rstgen_lowpower_set(&rstsig_saci1, rstgen_mode, !!(reset_mask & SDRV_AP_MODULE_SACI1_MASK)); #endif #ifdef APB_SACI2_BASE sdrv_rstgen_lowpower_set(&rstsig_saci2, rstgen_mode, !!(reset_mask & SDRV_AP_MODULE_SACI2_MASK)); #endif sdrv_rstgen_lowpower_set(&rstsig_dma_ap, rstgen_mode, !!(reset_mask & SDRV_AP_MODULE_DMA_MASK)); #ifdef APB_SEHC1_BASE sdrv_rstgen_lowpower_set(&rstsig_sehc1, rstgen_mode, !!(reset_mask & SDRV_AP_MODULE_SEHC1_MASK)); #endif #ifdef APB_SEHC2_BASE sdrv_rstgen_lowpower_set(&rstsig_sehc2, rstgen_mode, !!(reset_mask & SDRV_AP_MODULE_SEHC2_MASK)); #endif sdrv_rstgen_lowpower_set(&rstsig_usb, rstgen_mode, !!(reset_mask & SDRV_AP_MODULE_USB_MASK)); sdrv_rstgen_lowpower_set(&rstsig_seip, rstgen_mode, !!(reset_mask & SDRV_AP_MODULE_SEIP_MASK)); sdrv_rstgen_lowpower_set(&rstsig_lvds_ss, rstgen_mode, !!(reset_mask & SDRV_AP_MODULE_LVDS_MASK)); } #endif static void sdrv_power_regulator_pd_config(uint32_t pd_mask, sdrv_pmu_mode_e mode) { sdrv_pmu_pwrctrl_config_t pwrctrl_cfg; sdrv_pmu_pwron_config_t pwron_cfg; pwrctrl_cfg.ctrl_operate = SDRV_PMU_AUTO; pwron_cfg.ctrl_operate = SDRV_PMU_AUTO; /* power ctrl 0 - 3 */ pwrctrl_cfg.ctrl_status = (pd_mask & SDRV_PWR_CTRL0_PD_MASK) ? SDRV_PMU_CTRL_ON : SDRV_PMU_CTRL_OFF; sdrv_pmu_pwrctrl_config(SDRV_PMU_PWR_CTRL_0, mode, &pwrctrl_cfg); pwrctrl_cfg.ctrl_status = (pd_mask & SDRV_PWR_CTRL1_PD_MASK) ? SDRV_PMU_CTRL_ON : SDRV_PMU_CTRL_OFF; sdrv_pmu_pwrctrl_config(SDRV_PMU_PWR_CTRL_1, mode, &pwrctrl_cfg); pwrctrl_cfg.ctrl_status = (pd_mask & SDRV_PWR_CTRL2_PD_MASK) ? SDRV_PMU_CTRL_ON : SDRV_PMU_CTRL_OFF; sdrv_pmu_pwrctrl_config(SDRV_PMU_PWR_CTRL_2, mode, &pwrctrl_cfg); pwrctrl_cfg.ctrl_status = (pd_mask & SDRV_PWR_CTRL3_PD_MASK) ? SDRV_PMU_CTRL_ON : SDRV_PMU_CTRL_OFF; sdrv_pmu_pwrctrl_config(SDRV_PMU_PWR_CTRL_3, mode, &pwrctrl_cfg); /* power on 0 - 3 */ pwron_cfg.ctrl_status = (pd_mask & SDRV_PWR_ON0_PD_MASK) ? SDRV_PMU_CTRL_ON : SDRV_PMU_CTRL_OFF; sdrv_pmu_pwron_config(SDRV_PMU_PWR_ON_0, mode, &pwron_cfg); pwron_cfg.ctrl_status = (pd_mask & SDRV_PWR_ON1_PD_MASK) ? SDRV_PMU_CTRL_ON : SDRV_PMU_CTRL_OFF; sdrv_pmu_pwron_config(SDRV_PMU_PWR_ON_1, mode, &pwron_cfg); pwron_cfg.ctrl_status = (pd_mask & SDRV_PWR_ON2_PD_MASK) ? SDRV_PMU_CTRL_ON : SDRV_PMU_CTRL_OFF; sdrv_pmu_pwron_config(SDRV_PMU_PWR_ON_2, mode, &pwron_cfg); pwron_cfg.ctrl_status = (pd_mask & SDRV_PWR_ON3_PD_MASK) ? SDRV_PMU_CTRL_ON : SDRV_PMU_CTRL_OFF; sdrv_pmu_pwron_config(SDRV_PMU_PWR_ON_3, mode, &pwron_cfg); } static void sdrv_power_lowpower_enable(bool enable) { sdrv_smc_lowpower_enable(SDRV_SMC_SAF, enable); sdrv_smc_lowpower_enable(SDRV_SMC_AP, enable); } static void sdrv_power_lowpower_mode(sdrv_smc_mode_e mode) { sdrv_smc_set_lowpower_mode(SDRV_SMC_SAF, mode); sdrv_smc_set_lowpower_mode(SDRV_SMC_AP, mode); } static inline void sdrv_power_standby(void) { __asm volatile ( "dsb" ::: "memory" ); __asm volatile ( "wfi" ); __asm volatile ( "isb" ); } static inline uint32_t sdrv_power_iram_base(sdrv_iram_e iram) { switch (iram) { #ifdef APB_IRAMC1_BASE case SDRV_IRAM1: return APB_IRAMC1_BASE; #endif #ifdef APB_IRAMC2_BASE case SDRV_IRAM2: return APB_IRAMC2_BASE; #endif #ifdef APB_IRAMC3_BASE case SDRV_IRAM3: return APB_IRAMC3_BASE; #endif #ifdef APB_IRAMC4_BASE case SDRV_IRAM4: return APB_IRAMC4_BASE; #endif default: return 0; } } /** * @brief set iram mode before enter sleep/hibernate mode * * @param [in] iram iram1/2/3/4 * @param [in] lp_mode retention or power down */ static void sdrv_power_set_iram_lowpower_mode(sdrv_iram_e iram, sdrv_iram_lp_e lp_mode) { uint32_t base = sdrv_power_iram_base(iram); if (base) { RMWREG32(base + 0x4, 0, 3, lp_mode & 0x7); } } static void sdrv_power_iram_config_in_hib(uint32_t pd_mask) { sdrv_iram_lp_e mode; mode = (pd_mask & SDRV_IRAM1_PD_MASK) ? SDRV_IRAM_RETENTION2 : SDRV_IRAM_POWER_DOWN; sdrv_power_set_iram_lowpower_mode(SDRV_IRAM1, mode); mode = (pd_mask & SDRV_IRAM2_PD_MASK) ? SDRV_IRAM_RETENTION2 : SDRV_IRAM_POWER_DOWN; sdrv_power_set_iram_lowpower_mode(SDRV_IRAM2, mode); mode = (pd_mask & SDRV_IRAM3_PD_MASK) ? SDRV_IRAM_RETENTION2 : SDRV_IRAM_POWER_DOWN; sdrv_power_set_iram_lowpower_mode(SDRV_IRAM3, mode); mode = (pd_mask & SDRV_IRAM4_PD_MASK) ? SDRV_IRAM_RETENTION2 : SDRV_IRAM_POWER_DOWN; sdrv_power_set_iram_lowpower_mode(SDRV_IRAM4, mode); } static status_t sdrv_power_iram_reinit_after_hib(uint32_t pd_mask) { status_t ret = SDRV_STATUS_OK; if (!(pd_mask & SDRV_IRAM1_PD_MASK)) { ret |= sdrv_power_iram_reinit(SDRV_IRAM1); } if (!(pd_mask & SDRV_IRAM2_PD_MASK)) { ret |= sdrv_power_iram_reinit(SDRV_IRAM2); } if (!(pd_mask & SDRV_IRAM3_PD_MASK)) { ret |= sdrv_power_iram_reinit(SDRV_IRAM3); } if (!(pd_mask & SDRV_IRAM4_PD_MASK)) { ret |= sdrv_power_iram_reinit(SDRV_IRAM4); } return ret; } static void sdrv_power_saf_analog_power_down(sdrv_power_analog_t *config) { if (config) { sdrv_pmu_vd_sf_ana_enable(!config->vd_sf_pd); sdrv_pmu_por_sf_enable(!config->por_sf_pd); sdrv_pmu_rc24m_enable(!config->rc24m_pd); sdrv_pmu_bgr_sf_enable(!config->bgr_sf_pd); sdrv_pmu_bgr_ana_sf1_sf2_enable(!config->bgr_ana_pd); sdrv_pmu_bgr_ldo_enable(!config->bgr_ldo_pd); sdrv_pmu_analog_cven33_enable(!config->analog_cven33_pd); sdrv_pmu_vd_ap_enable(!config->vd_ap_pd); sdrv_pmu_por_ap_enable(!config->por_ap_pd); sdrv_pmu_bgr_ap_enable(!config->bgr_ap_pd); sdrv_pmu_bgr_disp_enable(!config->bgr_disp_pd); sdrv_pmu_bgr_sf_auto_disable(config->bgr_sf_auto_en); sdrv_pmu_bgr_ldo_auto_disable(config->bgr_ldo_auto_en); } } static void sdrv_power_saf_analog_power_on(void) { sdrv_pmu_vd_sf_ana_enable(true); sdrv_pmu_por_sf_enable(true); sdrv_pmu_rc24m_enable(true); sdrv_pmu_bgr_sf_enable(true); sdrv_pmu_bgr_ana_sf1_sf2_enable(true); sdrv_pmu_bgr_ldo_enable(true); sdrv_pmu_analog_cven33_enable(true); sdrv_pmu_vd_ap_enable(true); sdrv_pmu_por_ap_enable(true); sdrv_pmu_bgr_ap_enable(true); sdrv_pmu_bgr_disp_enable(true); } static void sdrv_power_get_core_rate(sdrv_core_clk_t *clk_info) { clk_info->sf_rate = sdrv_ckgen_bus_get_rate(CLK_NODE(g_ckgen_bus_cr5_sf), CKGEN_BUS_CLK_OUT_M); #if CONFIG_E3 || CONFIG_D3 clk_info->sp_rate = sdrv_ckgen_bus_get_rate(CLK_NODE(g_ckgen_bus_cr5_sp), CKGEN_BUS_CLK_OUT_M); #endif #if defined(CORE_SX0) || defined(CORE_SX1) clk_info->sx_rate = sdrv_ckgen_get_rate(CLK_NODE(g_ckgen_core_cr5_sx)); #endif } static status_t sdrv_power_set_core_rate(sdrv_core_clk_t *clk_info) { status_t ret = SDRV_STATUS_OK; ret |= sdrv_ckgen_bus_set_rate(CLK_NODE(g_ckgen_bus_cr5_sf), clk_info->sf_rate, CKGEN_BUS_DIV_4_2_1); #if CONFIG_E3 || CONFIG_D3 ret |= sdrv_ckgen_bus_set_rate(CLK_NODE(g_ckgen_bus_cr5_sp), clk_info->sp_rate, CKGEN_BUS_DIV_4_2_1); #endif #if defined(CORE_SX0) || defined(CORE_SX1) if (!sdrv_ckgen_slice_gated(CLK_NODE(g_ckgen_core_cr5_sx))) { ret |= sdrv_ckgen_set_rate(CLK_NODE(g_ckgen_core_cr5_sx), clk_info->sx_rate); } #endif return ret; } static status_t sdrv_power_pll_recfg_after_wakeup(void) { status_t ret = SDRV_STATUS_OK; for (uint32_t i = 0; i < g_pll_config.config_num; i++) { const sdrv_ckgen_rate_config_node_t *node = &g_pll_config.config_nodes[i]; ret = sdrv_pll_set_rate_with_dsm(node->clk_node, node->rate, node->node_cfg.pll); if (ret) { return ret; } } return ret; } #if CONFIG_E3 || CONFIG_D3 static void sdrv_power_get_rstsig_status(uint32_t *rstsig_status) { *rstsig_status = 0; #if defined(CORE_SP0) || defined(CORE_SP1) *rstsig_status |= (sdrv_rstgen_status(&rstsig_cr5_sp0) ? 0U : 0x1U); *rstsig_status |= (sdrv_rstgen_status(&rstsig_cr5_sp1) ? 0U : 0x2U); #endif #if defined(CORE_SX0) || defined(CORE_SX1) *rstsig_status |= (sdrv_rstgen_status(&rstsig_cr5_sx0) ? 0U : 0x4U); *rstsig_status |= (sdrv_rstgen_status(&rstsig_cr5_sx1) ? 0U : 0x8U); #endif #if APB_GAMA1_BASE *rstsig_status |= (sdrv_rstgen_status(&rstsig_gama1) ? 0U : 0x10U); #endif } static void sdrv_power_set_rstsig_status(uint32_t status) { #if APB_GAMA1_BASE if (status & 0x10U) sdrv_rstgen_deassert(&rstsig_gama1); #endif #if defined(CORE_SP0) || defined(CORE_SP1) if (status & 0x1U) sdrv_rstgen_deassert(&rstsig_cr5_sp0); if (status & 0x2U) sdrv_rstgen_deassert(&rstsig_cr5_sp1); #endif #if defined(CORE_SX0) || defined(CORE_SX1) if (status & 0x4U) sdrv_rstgen_deassert(&rstsig_cr5_sx0); if (status & 0x8U) sdrv_rstgen_deassert(&rstsig_cr5_sx1); #endif } #endif static void sdrv_power_get_ap_bus_clks(sdrv_ap_bus_clk_t *clk_info) { clk_info->ap_bus_rate = sdrv_ckgen_bus_get_rate(CLK_NODE(g_ckgen_bus_ap_bus), CKGEN_BUS_CLK_OUT_N); #if CONFIG_E3 || CONFIG_D3 clk_info->disp_bus_rate = sdrv_ckgen_bus_get_rate(CLK_NODE(g_ckgen_bus_disp_bus), CKGEN_BUS_CLK_OUT_N); clk_info->seip_bus_rate = sdrv_ckgen_bus_get_rate(CLK_NODE(g_ckgen_bus_seip), CKGEN_BUS_CLK_OUT_N); #endif } static status_t sdrv_power_set_ap_bus_clks(sdrv_ap_bus_clk_t *clk_info) { status_t ret = SDRV_STATUS_OK; ret |= sdrv_ckgen_bus_set_rate(CLK_NODE(g_ckgen_bus_ap_bus), clk_info->ap_bus_rate, CKGEN_BUS_DIV_4_2_1); #if CONFIG_E3 || CONFIG_D3 ret |= sdrv_ckgen_bus_set_rate(CLK_NODE(g_ckgen_bus_disp_bus), clk_info->disp_bus_rate, CKGEN_BUS_DIV_4_2_1); if (!sdrv_ckgen_slice_gated(CLK_NODE(g_ckgen_bus_seip))) { ret |= sdrv_ckgen_bus_set_rate(CLK_NODE(g_ckgen_bus_seip), clk_info->seip_bus_rate, CKGEN_BUS_DIV_4_2_1); } #endif return ret; } /* wakeup event is asserted at the end of lp handshake with rstgen/ckgen and before pmu SMC may wake up rstgen/ckgen meanwhile request PMU to sleep. SW should add this work around to all wakeup irq handlers if lowpower sequence is enable. wakeup irq handler: Step-1: check smc_dbg_mon(sf): {12'b0, saf_rstgen_swm_ack,saf_rstgen_swm_i[3:0], saf_rstgen_swm_req,saf_rstgen_swm_o[3:0], saf_ckgen_swm_ack,saf_ckgen_swm_i[3:0], saf_ckgen_swm_req,saf_ckgen_swm_o[3:0]} Possible Values -- 0x0: ckgen_sf and rstgen_sf lowpower sequence haven't started, lowpower sequence abort -- 0x21: ckgen_sf has entered lowpower and wakeup to RUN state, rstgen_sf lowpower hasn't started, SMC lowpower sequence abort. -- 0x8421: ckgen_sf and rstgen_sf have entered lowpower state and woken up to RUN state -- other values: un-expected failure SW action -- 0x0|0x21|0x8421: go ahead -- other values: exception, need to debug Step-2: check smc_dbg_mon(ap): {12'b0, ap_rstgen_swm_ack,ap_rstgen_swm_i[3:0], ap_rstgen_swm_req,ap_rstgen_swm_o[3:0], ap_ckgen_swm_ack,ap_ckgen_swm_i[3:0], ap_ckgen_swm_req,ap_ckgen_swm_o[3:0]} Possible Values -- 0x0: ckgen_ap and ckgen_ap lowpower sequence haven't started, lowpower sequence abort -- 0x21: ckgen_ap has entered lowpower and wakeup to RUN state, rstgen_ap lowpower hasn't start, SMC lowpower sequence abort. -- 0x421: AP was reset, and AP lowpower seq is abort at this time (ckgen_ap entered lowpower and wakeup to RUN, rstgen_ap not start) -- 0x401: ckgen_ap and rstgen_ap entered lowpower and wakeup to RUN, then AP domain was reset, and AP lowpower sequence hasn't start at this time -- 0x8421: ckgen_ap and rstgen_ap have entered lowpower state and wake up to RUN state -- other values: un-expected failure SW action -- 0x0|0x21|0x421|0x401|0x8421: go ahead -- other values: exception, need to debug Step-3: check smc_dbg_mon(pmu): {22'b0, pmu_swm_ack,pmu_swm_i[3:0], pmu_swm_req,pmu_swm_o[3:0]} Possible Values -- 0x21: PMU is in RUN state -- 0x32|0x34: smc sending swm_req = slp/hib, but PMU hasn't ACK -- 0x242|0x284: at the end of lp handshake, smc has de-assert swm_req, PMU swm_ack still 1 -- 0x42|0x84: lowpower handshake is done, PMU is in sleep or hibernate state now -- other values: exception, need to debug SW action -- 0x32|0x34|0x242|0x284: 1. Polling smc_dbg_mon = 0x42|0x84 to wait PMU lowpower handshake done 2. Configure SMC sw_swm register to send RUN request to PMU manually (sw_swm_en bit must be clear after handshake done) 3. Polling smc_dbg_mon = 0x21 to wait PMU wakeup handshake done 4. Polling ap_ss_rdy = 1 if AP power|ap_por_b is configured to OFF in lowpower state -- 0x42|0x84: 2 ~ 4 steps above -- 0x21: go ahead -- other values: exception, need to debug" */ static status_t sdrv_power_swm_check_after_exit_wfi(void) { volatile uint32_t dbg_mon; volatile uint32_t timeout; timeout = SDRV_POWER_POLL_COUNT; do { dbg_mon = sdrv_smc_debug_monitor(SDRV_SMC_DBG_HK_SAF); timeout--; ssdk_printf(SSDK_DEBUG, "SMC DBG SAF: 0x%08x\r\n", dbg_mon); } while (dbg_mon != 0x0 && dbg_mon != 0x21 && dbg_mon != 0x8421 && timeout > 0); if (timeout == 0) { return SDRV_POWER_WAKEUP_STATUS_ERROR; } timeout = SDRV_POWER_POLL_COUNT; do { dbg_mon = sdrv_smc_debug_monitor(SDRV_SMC_DBG_HK_AP); timeout--; ssdk_printf(SSDK_DEBUG, "SMC DBG AP: 0x%08x\r\n", dbg_mon); } while (dbg_mon != 0x0 && dbg_mon != 0x21 && dbg_mon != 0x421 && dbg_mon != 0x401 && dbg_mon != 0x8421 && timeout > 0); if (timeout == 0) { return SDRV_POWER_WAKEUP_STATUS_ERROR; } timeout = SDRV_POWER_POLL_COUNT; while ((--timeout) > 0) { dbg_mon = sdrv_smc_debug_monitor(SDRV_SMC_DBG_HK_PMU); ssdk_printf(SSDK_DEBUG, "SMC DBG PMU: 0x%08x\r\n", dbg_mon); switch (dbg_mon) { case 0x21: case 0x32: case 0x34: case 0x242: case 0x284: case 0x221: case 0x294: case 0x252: break; case 0x42: case 0x84: ssdk_printf(SSDK_INFO, "PM: sw trigger pmu back to run.\r\n"); sdrv_smc_trigger_software_handshake(SDRV_SMC_HK_PMU, SDRV_SMC_SWM_RUN); break; default: ssdk_printf(SSDK_EMERG, "SMC handshake PMU status wrong 0x%x\r\n", dbg_mon); return SDRV_POWER_PMU_STATUS_ERROR; break; } if (dbg_mon == 0x21) { break; } } if (timeout == 0) { return SDRV_POWER_WAKEUP_STATUS_ERROR; } if (!sdrv_power_wait(APB_RSTGEN_SF_BASE + 0x204U, 31, 1, SDRV_POWER_POLL_COUNT)) { return SDRV_POWER_AP_STATUS_ERROR; } #ifdef APB_RSTGEN_AP_BASE if (!sdrv_power_wait(APB_RSTGEN_AP_BASE + 0x204U, 31, 1, SDRV_POWER_POLL_COUNT)) { return SDRV_POWER_AP_STATUS_ERROR; } #endif return SDRV_STATUS_OK; } static status_t sdrv_power_check_soc_in_run_status(void) { uint32_t val; val = sdrv_smc_status_monitor(); if (val != SDRV_SMC_RUN_STATUS) { return SDRV_POWER_SMC_STATUS_ERROR; } val = sdrv_pmu_get_state(); if ((val & 0x7U) != 0x1U) { return SDRV_POWER_PMU_STATUS_ERROR; } return SDRV_STATUS_OK; } /** * @brief Initialize clock/reset/power config under sleep and hibernate mode. * * This function will mask all interrupts and gate all xcg clock expect for wakeup modules. It will reset all * modules expect that need wakeup and user defined not reset in low power mode. According to user configration, * config smc sleep/hibernate mode core power switch and pmu pwr ctrl/pwr on status. * * @param [in] sleep_cfg config for sleep mode * @param [in] hib_cfg config for hibernate mode * @return SDRV_STATUS_OK or error code */ status_t sdrv_power_init(sdrv_sleep_mode_config_t *sleep_cfg, sdrv_hibernate_mode_config_t *hib_cfg) { sdrv_wakeup_src_e *wk_source; uint32_t ps_pd_mask; ps_pd_mask = hib_cfg->core_pd_mask; #if CONFIG_E3 || CONFIG_D3 ps_pd_mask |= SDRV_SF_PD_MASK; #endif #if CONFIG_E3L if (IS_1P0) { ps_pd_mask |= (SDRV_SF_PD_MASK | SDRV_SF_BOOT_PD_MASK); } #endif /* bypass offline lbist */ RMWREG32(APB_EFUSEC_BASE + 0x1290, 0, 1, 0); memset(&g_power_ctrl, 0x0, sizeof(sdrv_power_ctrl_t)); sdrv_power_get_core_rate(&g_power_ctrl.soc_default_clks.core_clks); sdrv_power_get_ap_bus_clks(&g_power_ctrl.soc_default_clks.ap_bus_clks); g_power_ctrl.iram_hib_pd_mask = hib_cfg->iram_pd_mask; g_power_ctrl.analog_cfg = hib_cfg->analog_power; g_power_ctrl.power_switch_hib_pd_mask = ps_pd_mask | sdrv_power_get_core_power_switch_runmode_config(); sdrv_smc_all_wakeup_interrupt_disable(); /* Config all PCG/BCG/CCG disable in SLEEP&HIB mode */ sdrv_power_all_xcg_gate_in_lowpower(APB_CKGEN_SF_BASE, SDRV_SF_CKGEN_PCG_NUM, SDRV_SF_CKGEN_BCG_NUM, SDRV_SF_CKGEN_CCG_NUM); #ifdef APB_CKGEN_AP_BASE sdrv_power_all_xcg_gate_in_lowpower(APB_CKGEN_AP_BASE, 60, 7, 0); #endif wk_source = sleep_cfg->wakeup_srcs; while (*wk_source != SDRV_WAKEUP_END) { sdrv_power_enable_wakeup_source_pcg(*wk_source, SDRV_SLEEP_MODE); wk_source++; } sdrv_power_pll_power_down_mask(sleep_cfg->pll_pd_mask, SDRV_SLEEP_MODE); sdrv_power_xtal_24m_config(!(sleep_cfg->xtal_24m_disable), SDRV_SLEEP_MODE); wk_source = hib_cfg->wakeup_srcs; while (*wk_source != SDRV_WAKEUP_END) { sdrv_power_enable_wakeup_source_pcg(*wk_source, SDRV_HIBERNATE_MODE); wk_source++; } sdrv_power_pll_power_down_mask(hib_cfg->pll_pd_mask, SDRV_HIBERNATE_MODE); sdrv_power_xtal_24m_config(!(hib_cfg->xtal_24m_disable), SDRV_HIBERNATE_MODE); sdrv_power_saf_module_reset_config(sleep_cfg->sf_module_reset_mask, SDRV_SLEEP_MODE); sdrv_power_saf_module_reset_config(hib_cfg->sf_module_reset_mask, SDRV_HIBERNATE_MODE); #ifdef APB_RSTGEN_AP_BASE sdrv_power_ap_module_reset_config(sleep_cfg->ap_module_reset_mask, SDRV_SLEEP_MODE); sdrv_power_ap_module_reset_config(hib_cfg->ap_module_reset_mask, SDRV_HIBERNATE_MODE); #endif #if CONFIG_E3 || CONFIG_D3 if (!hib_cfg->ap_domain_powered) { ps_pd_mask |= SDRV_AP_DISP_PD_MASK; g_power_ctrl.power_switch_hib_pd_mask |= SDRV_AP_DISP_PD_MASK; } /* configure rstgen_ap: in case that the ap_ss power switch is OFF in hibernate mode, the ap_ss partition rst (rstgen_ap.mission_rst_b[1]) should be configured to OFF in hibernate mode otherwise the wdt and por in the ap_ss cannot be reset after power ON */ /* AP module[10:3] should assert in hibernate */ if (!(g_power_ctrl.power_switch_hib_pd_mask & SDRV_AP_DISP_PD_MASK)) { sdrv_rstgen_lowpower_set(&rstsig_ap_mission1, RESET_LP_HIB, 0); } if (!(g_power_ctrl.power_switch_hib_pd_mask & SDRV_GAMA1_PD_MASK)) { /* rstgen_sf.mission_rst_b[6] reset gama_1 misc logics, should be asserted in hibernate mode */ sdrv_rstgen_lowpower_set(&rstsig_saf_mission6, RESET_LP_HIB, 0); } /* iso_dis recommand set to >= 4 */ sdrv_smc_power_switch_delay_config(SDRV_SMC_POWER_SWITCH_SF, 0x7, 0x7, 0x7, 0x4); sdrv_smc_power_switch_delay_config(SDRV_SMC_POWER_SWITCH_SP, 0x7, 0x7, 0x7, 0x4); sdrv_smc_power_switch_delay_config(SDRV_SMC_POWER_SWITCH_SX, 0x7, 0x7, 0x7, 0x4); sdrv_smc_power_switch_delay_config(SDRV_SMC_POWER_SWITCH_GAMA1, 0x7, 0x7, 0x7, 0x5); sdrv_smc_power_switch_delay_config(SDRV_SMC_POWER_SWITCH_AP_DISP, 0x7, 0x7, 0x7, 0x4); /* irq mask delay only set to 0 */ sdrv_smc_domain_misc_config(SDRV_SMC_SAF, false, 0x0, false); sdrv_smc_domain_misc_config(SDRV_SMC_AP, false, 0x0, false); #endif /* #if CONFIG_E3 || CONFIG_D3 */ #if CONFIG_E3L /* sf boot power down, module[16:0] and latent must assert in hib */ if (!(ps_pd_mask & SDRV_SF_BOOT_PD_MASK)) { sdrv_rstgen_lowpower_set(&rstsig_latent, RESET_LP_HIB, 0); } /* ap_mix power down, module[19:16] and mission5 must assert in hib */ if (!(ps_pd_mask & SDRV_AP_MIX_PD_MASK)) { sdrv_rstgen_lowpower_set(&rstsig_mission5, RESET_LP_HIB, 0); } /* iso_dis recommand set to >= 4 */ sdrv_smc_power_switch_delay_config(SDRV_SMC_POWER_SWITCH_SF, 0x7, 0x7, 0x7, 0x4); sdrv_smc_power_switch_delay_config(SDRV_SMC_POWER_SWITCH_SF_BOOT, 0x7, 0x7, 0x7, 0x15); sdrv_smc_power_switch_delay_config(SDRV_SMC_POWER_SWITCH_AP_MIX, 0x7, 0x7, 0x7, 0x4); if (IS_1P0) { /* irq mask delay only set to 0 */ sdrv_smc_domain_misc_config(SDRV_SMC_SAF, false, 0x0, false); sdrv_smc_domain_misc_config(SDRV_SMC_AP, false, 0x0, false); } else if (IS_1P1) { sdrv_smc_domain_misc_config(SDRV_SMC_SAF, false, 0xf, false); sdrv_smc_domain_misc_config(SDRV_SMC_AP, false, 0xf, false); } #endif sdrv_smc_pre_divider_config(0x1f, 0xf); sdrv_smc_set_primary_core(SDRV_SMC_AP, SDRV_SMC_CORE_SF); sdrv_power_core_power_gate_config(ps_pd_mask, SDRV_SMC_HIBERNATE); sdrv_smc_rc24m_hibernate_enable(!(hib_cfg->rc_24m_disable)); sdrv_power_regulator_pd_config(hib_cfg->regulator_pd_mask, SDRV_PMU_HIBERNATE); sdrv_pmu_target_power_on_config(SDRV_PMU_AP, SDRV_PMU_HIBERNATE, !!hib_cfg->ap_domain_powered); return SDRV_STATUS_OK; } /** * @brief Set soc to specific power mode. * * This function config SMC enable wfi detect and excute wfi instrcut. After all core enter wfi, it will start hardware * operation. Before enter sleep, software config all iram to retention mode. Before enter hibernate, software power down * iram as pre-defined, and power down analog part. Then use SVC interrupt to save all core registers. After wakeup from * sleep/hibernate, it will return from this call. Iram and analog will be powered again. If call to enter RTC mode, it * will power down at once. * * @param [in] mode mode defined in sdrv_power_mode_e. * @return SDRV_STATUS_OK or error code. */ status_t sdrv_power_set_mode(sdrv_power_mode_e mode) { status_t ret = SDRV_STATUS_OK; irq_state_t irq_state; static sdrv_core_clk_t clk_24m = { .sf_rate = CLK_24M_RATE, .sp_rate = CLK_24M_RATE, .sx_rate = CLK_24M_RATE, }; if (mode == SDRV_RUN_MODE) { return SDRV_STATUS_OK; } irq_state = arch_irq_save(); sdrv_smc_all_interrupt_monitor_clear(); switch (mode) { case SDRV_SLEEP_MODE: sdrv_power_get_core_rate(&g_power_ctrl.core_clks); sdrv_power_lowpower_mode(SDRV_SMC_SLEEP); sdrv_power_lowpower_enable(true); for (uint32_t i = SDRV_IRAM1; i <= SDRV_IRAM4; i++) { sdrv_power_set_iram_lowpower_mode((sdrv_iram_e)i, SDRV_IRAM_RETENTION2); } RTC_REG_PARITY_ERR_INT_DIS(); sdrv_power_rstsig_handler(&g_power_ctrl, SDRV_SLEEP_MODE, 0); ret |= sdrv_power_set_core_rate(&clk_24m); sdrv_power_standby(); ret |= sdrv_power_pll_recfg_after_wakeup(); ret |= sdrv_power_set_core_rate(&g_power_ctrl.core_clks); break; case SDRV_HIBERNATE_MODE: sdrv_power_get_core_rate(&g_power_ctrl.core_clks); sdrv_power_lowpower_mode(SDRV_SMC_HIBERNATE); sdrv_power_lowpower_enable(true); sdrv_power_iram_config_in_hib(g_power_ctrl.iram_hib_pd_mask); sdrv_power_saf_analog_power_down(&g_power_ctrl.analog_cfg); sdrv_power_get_ap_bus_clks(&g_power_ctrl.ap_bus_clks); #if CONFIG_E3 || CONFIG_D3 sdrv_power_get_rstsig_status(&g_power_ctrl.core_gama_rstsig); ret |= sdrv_power_core_power_switch_before_hib(g_power_ctrl.power_switch_hib_pd_mask); #endif #if CONFIG_E3L if (IS_1P0) { ret |= sdrv_power_core_power_switch_before_hib(g_power_ctrl.power_switch_hib_pd_mask); } #endif arm_context_save(); RTC_REG_PARITY_ERR_INT_DIS(); sdrv_power_rstsig_handler(&g_power_ctrl, SDRV_HIBERNATE_MODE, 0); if (arm_context_read_flag() != CONTEXT_RESTORE_FLAG) { arm_context_write_flag(CONTEXT_RESTORE_FLAG); #if CONFIG_E3L ret |= sdrv_ckgen_bus_set_rate(CLK_NODE(g_ckgen_bus_ap_bus), CLK_24M_RATE, CKGEN_BUS_DIV_4_2_1); #endif ret |= sdrv_power_set_core_rate(&clk_24m); sdrv_power_standby(); } ret |= sdrv_power_set_core_rate(&g_power_ctrl.core_clks); break; case SDRV_RTC_MODE: sdrv_pmu_power_down(); while (1) { sdrv_power_standby(); } break; default: arch_irq_restore(irq_state); return SDRV_STATUS_INVALID_PARAM; } sdrv_smc_record_interrupt_monitor_status(); #if CONFIG_E3 || CONFIG_D3 if (!(g_power_ctrl.power_switch_hib_pd_mask & SDRV_AP_DISP_PD_MASK)) { ret |= sdrv_power_software_apss_on(); } ret |= sdrv_power_swm_check_after_exit_wfi(); #endif #if CONFIG_E3L if (IS_1P0) { ret |= sdrv_power_swm_check_after_exit_wfi(); } #endif ret |= sdrv_power_check_soc_in_run_status(); RTC_REG_PARITY_ERR_INT_EN(); sdrv_power_rstsig_handler(&g_power_ctrl, mode, 1); for (uint32_t i = SDRV_IRAM1; i <= SDRV_IRAM4; i++) { sdrv_power_set_iram_lowpower_mode((sdrv_iram_e)i, SDRV_IRAM_IDLE); } if (mode == SDRV_HIBERNATE_MODE) { sdrv_power_saf_analog_power_on(); ret |= sdrv_power_iram_reinit_after_hib(g_power_ctrl.iram_hib_pd_mask); #if CONFIG_E3 || CONFIG_D3 ret |= sdrv_power_core_power_switch_after_hib(g_power_ctrl.power_switch_hib_pd_mask); ret |= sdrv_power_pll_recfg_after_wakeup(); ret |= sdrv_power_set_ap_bus_clks(&g_power_ctrl.ap_bus_clks); sdrv_power_set_rstsig_status(g_power_ctrl.core_gama_rstsig); #endif #if CONFIG_E3L if (IS_1P0) { ret |= sdrv_power_core_power_switch_after_hib(g_power_ctrl.power_switch_hib_pd_mask); } ret |= sdrv_power_pll_recfg_after_wakeup(); ret |= sdrv_power_set_ap_bus_clks(&g_power_ctrl.ap_bus_clks); #endif } sdrv_power_lowpower_enable(false); arm_context_write_flag(0); arch_irq_restore(irq_state); return ret; } status_t sdrv_power_clock_set_mode(sdrv_clock_mode_e mode) { status_t ret = SDRV_STATUS_OK; sdrv_core_clk_t core_clks; sdrv_ap_bus_clk_t ap_bus_clks; switch (mode) { case SDRV_CLOCK_NORMAL: core_clks = g_power_ctrl.soc_default_clks.core_clks; ap_bus_clks = g_power_ctrl.soc_default_clks.ap_bus_clks; break; case SDRV_CLOCK_MEDIUM: core_clks.sf_rate = g_power_ctrl.soc_default_clks.core_clks.sf_rate / 2; core_clks.sp_rate = g_power_ctrl.soc_default_clks.core_clks.sp_rate / 2; core_clks.sx_rate = g_power_ctrl.soc_default_clks.core_clks.sx_rate / 2; ap_bus_clks.ap_bus_rate = g_power_ctrl.soc_default_clks.ap_bus_clks.ap_bus_rate / 2; ap_bus_clks.disp_bus_rate = g_power_ctrl.soc_default_clks.ap_bus_clks.disp_bus_rate / 2; ap_bus_clks.seip_bus_rate = g_power_ctrl.soc_default_clks.ap_bus_clks.seip_bus_rate / 2; break; case SDRV_CLOCK_LOW: core_clks.sf_rate = CLK_24M_RATE; core_clks.sp_rate = CLK_24M_RATE; core_clks.sx_rate = CLK_24M_RATE; ap_bus_clks.ap_bus_rate = CLK_24M_RATE; ap_bus_clks.disp_bus_rate = CLK_24M_RATE; ap_bus_clks.seip_bus_rate = CLK_24M_RATE; break; default: break; } #if CONFIG_ARM_WITH_PMU pmu_stop_clear_cycle_cntr(); #endif ret |= sdrv_power_set_core_rate(&core_clks); ret |= sdrv_power_set_ap_bus_clks(&ap_bus_clks); return ret; } /** * @brief Reinit specific iram. * * This function reinit specific iram. If iram is power down in hibernate, after wakeup, you need call this function before * use it. * * @param [in] iram iram defined in sdrv_iram_e. * @return SDRV_STATUS_OK or error code. */ status_t sdrv_power_iram_reinit(sdrv_iram_e iram) { status_t ret = SDRV_STATUS_OK; uint32_t base = sdrv_power_iram_base(iram); if (base) { RMWREG32(base, 0, 1, 1); if (!sdrv_power_wait(base, 0, 0, SDRV_POWER_POLL_COUNT)) { ret = SDRV_POWER_IRAM_REINIT_TIMEOUT; } } return ret; } status_t sdrv_power_rom_disable(void) { RMWREG32(APB_IROMC_BASE + 0x8, 0, 2, 0x1); return SDRV_STATUS_OK; } status_t sdrv_power_usb_power_down(void) { RMWREG32(PHY_NCR_CTL_9, 6, 2, 0x1); writel(0x1000a5a5, PHY_NCR_CTL_6); RMWREG32(PHY_NCR_CTL_6, 24, 8, 0x15); writel(0x38780000, PHY_NCR_CTL_0); return SDRV_STATUS_OK; } status_t sdrv_power_dcdc_config(paddr_t dcdc_base, sdrv_power_dcdc_mode_e mode, sdrv_power_dcdc_reg_e dcdc_reg, uint8_t cfg_val) { uint32_t offset; switch (dcdc_reg) { case DCDC_REG_0: RMWREG32(dcdc_base + ANA_COM_CFG, DCDC_REG_0_LSB, 8, cfg_val); break; case DCDC_REG_7: RMWREG32(dcdc_base + ANA_COM_CFG, DCDC_REG_7_LSB, 8, cfg_val); break; case DCDC_REG_8: RMWREG32(dcdc_base + ANA_COM_CFG, DCDC_REG_8_LSB, 8, cfg_val); break; case DCDC_REG_1: case DCDC_REG_2: case DCDC_REG_3: offset = (mode == DCDC_HP_MODE) ? HP_MOD_CFG0 : LP_MOD_CFG0; if (dcdc_reg == DCDC_REG_1) { RMWREG32(dcdc_base + offset, DCDC_REG_1_LSB, 8, cfg_val); } else if (dcdc_reg == DCDC_REG_2) { RMWREG32(dcdc_base + offset, DCDC_REG_2_LSB, 8, cfg_val); } else { RMWREG32(dcdc_base + offset, DCDC_REG_3_LSB, 8, cfg_val); } break; case DCDC_REG_4: case DCDC_REG_5: case DCDC_REG_6: offset = (mode == DCDC_HP_MODE) ? HP_MOD_CFG1 : LP_MOD_CFG1; if (dcdc_reg == DCDC_REG_4) { RMWREG32(dcdc_base + offset, DCDC_REG_4_LSB, 8, cfg_val); } else if (dcdc_reg == DCDC_REG_5) { RMWREG32(dcdc_base + offset, DCDC_REG_5_LSB, 8, cfg_val); } else { RMWREG32(dcdc_base + offset, DCDC_REG_6_LSB, 8, cfg_val); } break; default: break; } return SDRV_STATUS_OK; }