2280 lines
79 KiB
C
2280 lines
79 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"
|
|
|
|
extern int arm_saveusercontext(uint32_t *saveregs);
|
|
extern void sdrv_power_tcm_save(void);
|
|
extern uint32_t cpu_regs[ARM_TOTAL_CONTEXT_REGS + MPUCONTEXT_REGS];
|
|
|
|
#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
|
|
|
|
/* weak function, use for store tcm data */
|
|
sdrv_power_tcm_save();
|
|
|
|
/* switch to svc save core registers */
|
|
arm_saveusercontext(cpu_regs);
|
|
|
|
if (arm_context_read_flag() != CONTEXT_RESTORE_FLAG) {
|
|
RTC_REG_PARITY_ERR_INT_DIS();
|
|
sdrv_power_rstsig_handler(&g_power_ctrl, SDRV_HIBERNATE_MODE, 0);
|
|
|
|
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;
|
|
}
|