Files
E3/e3_176_ref/drivers/source/power/sdrv_power.c
2025-10-21 19:40:27 +08:00

2271 lines
78 KiB
C

/**
* @file sdrv_power.c
* @brief Sdrv power driver source.
*
* @copyright Copyright (c) 2022 Semidrive Semiconductor.
* All rights reserved.
*/
#include <string.h>
#include <armv7-r/irq.h>
#include <armv7-r/pmu.h>
#include <sdrv_power.h>
#include <sdrv_ckgen.h>
#include <sdrv_rstgen.h>
#include <sdrv_rtc.h>
#include <clock_ip.h>
#include <reset_ip.h>
#include <irq_num.h>
#include <reg.h>
#include <regs_base.h>
#include <core_id.h>
#include <part.h>
#include <debug.h>
#include <bits.h>
#include <common.h>
#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;
}