Unverified Commit 44b935c0 authored by Antonio Niño Díaz's avatar Antonio Niño Díaz Committed by GitHub
Browse files

Merge pull request #1789 from Anson-Huang/lpm

Add power optimization for i.MX8QM/i.MX8QX
parents 7d388400 e6cf7a46
......@@ -32,8 +32,22 @@ void __dead2 imx_system_reset(void)
int imx_validate_power_state(unsigned int power_state,
psci_power_state_t *req_state)
{
/* TODO */
return PSCI_E_INVALID_PARAMS;
int pwr_lvl = psci_get_pstate_pwrlvl(power_state);
int pwr_type = psci_get_pstate_type(power_state);
int state_id = psci_get_pstate_id(power_state);
if (pwr_lvl > PLAT_MAX_PWR_LVL)
return PSCI_E_INVALID_PARAMS;
if (pwr_type == PSTATE_TYPE_POWERDOWN) {
req_state->pwr_domain_state[MPIDR_AFFLVL0] = PLAT_MAX_OFF_STATE;
if (!state_id)
req_state->pwr_domain_state[MPIDR_AFFLVL1] = PLAT_MAX_RET_STATE;
else
req_state->pwr_domain_state[MPIDR_AFFLVL1] = PLAT_MAX_OFF_STATE;
}
return PSCI_E_SUCCESS;
}
void imx_get_sys_suspend_power_state(psci_power_state_t *req_state)
......
......@@ -10,6 +10,11 @@
#include <drivers/arm/gicv3.h>
#include <lib/psci/psci.h>
struct plat_gic_ctx {
gicv3_redist_ctx_t rdist_ctx[PLATFORM_CORE_COUNT];
gicv3_dist_ctx_t dist_ctx;
};
unsigned int plat_calc_core_pos(uint64_t mpidr);
void imx_mailbox_init(uintptr_t base_addr);
void plat_gic_driver_init(void);
......@@ -24,5 +29,7 @@ int imx_validate_power_state(unsigned int power_state,
psci_power_state_t *req_state);
void imx_get_sys_suspend_power_state(psci_power_state_t *req_state);
bool imx_is_wakeup_src_irqsteer(void);
void plat_gic_save(unsigned int proc_num, struct plat_gic_ctx *ctx);
void plat_gic_restore(unsigned int proc_num, struct plat_gic_ctx *ctx);
#endif /* PLAT_IMX8_H */
......@@ -73,3 +73,19 @@ void plat_gic_pcpu_init(void)
{
gicv3_rdistif_init(plat_my_core_pos());
}
void plat_gic_save(unsigned int proc_num, struct plat_gic_ctx *ctx)
{
/* save the gic rdist/dist context */
for (int i = 0; i < PLATFORM_CORE_COUNT; i++)
gicv3_rdistif_save(i, &ctx->rdist_ctx[i]);
gicv3_distif_save(&ctx->dist_ctx);
}
void plat_gic_restore(unsigned int proc_num, struct plat_gic_ctx *ctx)
{
/* restore the gic rdist/dist context */
gicv3_distif_init_restore(&ctx->dist_ctx);
for (int i = 0; i < PLATFORM_CORE_COUNT; i++)
gicv3_rdistif_init_restore(i, &ctx->rdist_ctx[i]);
}
......@@ -8,6 +8,21 @@
#include "imx8_mu.h"
void MU_Resume(uint32_t base)
{
uint32_t reg, i;
reg = mmio_read_32(base + MU_ACR_OFFSET1);
/* Clear GIEn, RIEn, TIEn, GIRn and ABFn. */
reg &= ~(MU_CR_GIEn_MASK1 | MU_CR_RIEn_MASK1 | MU_CR_TIEn_MASK1
| MU_CR_GIRn_MASK1 | MU_CR_Fn_MASK1);
mmio_write_32(base + MU_ACR_OFFSET1, reg);
/* Enable all RX interrupts */
for (i = 0; i < MU_RR_COUNT; i++)
MU_EnableRxFullInt(base, i);
}
void MU_EnableRxFullInt(uint32_t base, uint32_t index)
{
uint32_t reg = mmio_read_32(base + MU_ACR_OFFSET1);
......
......@@ -33,3 +33,4 @@ void MU_SendMessage(uint32_t base, uint32_t regIndex, uint32_t msg);
void MU_ReceiveMsg(uint32_t base, uint32_t regIndex, uint32_t *msg);
void MU_EnableGeneralInt(uint32_t base, uint32_t index);
void MU_EnableRxFullInt(uint32_t base, uint32_t index);
void MU_Resume(uint32_t base);
......@@ -49,11 +49,7 @@ const static int imx8qm_cci_map[] = {
};
static const mmap_region_t imx_mmap[] = {
MAP_REGION_FLAT(IMX_BOOT_UART_BASE, IMX_BOOT_UART_SIZE, MT_DEVICE | MT_RW),
MAP_REGION_FLAT(SC_IPC_BASE, SC_IPC_SIZE, MT_DEVICE | MT_RW),
MAP_REGION_FLAT(PLAT_GICD_BASE, PLAT_GICD_SIZE, MT_DEVICE | MT_RW),
MAP_REGION_FLAT(PLAT_GICR_BASE, PLAT_GICR_SIZE, MT_DEVICE | MT_RW),
MAP_REGION_FLAT(PLAT_CCI_BASE, PLAT_CCI_SIZE, MT_DEVICE | MT_RW),
MAP_REGION_FLAT(IMX_REG_BASE, IMX_REG_SIZE, MT_DEVICE | MT_RW),
{0}
};
......@@ -324,6 +320,10 @@ void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
/* turn on MU1 for non-secure OS/Hypervisor */
sc_pm_set_resource_power_mode(ipc_handle, SC_R_MU_1A, SC_PM_PW_MODE_ON);
/* Turn on GPT_0's power & clock for non-secure OS/Hypervisor */
sc_pm_set_resource_power_mode(ipc_handle, SC_R_GPT_0, SC_PM_PW_MODE_ON);
sc_pm_clock_enable(ipc_handle, SC_R_GPT_0, SC_PM_CLK_PER, true, 0);
mmio_write_32(IMX_GPT_LPCG_BASE, mmio_read_32(IMX_GPT_LPCG_BASE) | (1 << 25));
/*
* create new partition for non-secure OS/Hypervisor
......
......@@ -17,6 +17,8 @@
#include <plat_imx8.h>
#include <sci/sci.h>
#include "../../common/sci/imx8_mu.h"
#define CORE_PWR_STATE(state) \
((state)->pwr_domain_state[MPIDR_AFFLVL0])
#define CLUSTER_PWR_STATE(state) \
......@@ -29,44 +31,70 @@ const static int ap_core_index[PLATFORM_CORE_COUNT] = {
SC_R_A53_3, SC_R_A72_0, SC_R_A72_1,
};
/* save gic dist/redist context when GIC is poewr down */
static struct plat_gic_ctx imx_gicv3_ctx;
static unsigned int gpt_lpcg, gpt_reg[2];
static void imx_enable_irqstr_wakeup(void)
{
uint32_t irq_mask;
gicv3_dist_ctx_t *dist_ctx = &imx_gicv3_ctx.dist_ctx;
/* put IRQSTR into ON mode */
sc_pm_set_resource_power_mode(ipc_handle, SC_R_IRQSTR_SCU2, SC_PM_PW_MODE_ON);
/* enable the irqsteer to handle wakeup irq */
mmio_write_32(IMX_WUP_IRQSTR_BASE, 0x1);
for (int i = 0; i < 15; i++) {
irq_mask = dist_ctx->gicd_isenabler[i];
mmio_write_32(IMX_WUP_IRQSTR_BASE + 0x3c - 0x4 * i, irq_mask);
}
/* set IRQSTR low power mode */
if (imx_is_wakeup_src_irqsteer())
sc_pm_set_resource_power_mode(ipc_handle, SC_R_IRQSTR_SCU2, SC_PM_PW_MODE_STBY);
else
sc_pm_set_resource_power_mode(ipc_handle, SC_R_IRQSTR_SCU2, SC_PM_PW_MODE_OFF);
}
static void imx_disable_irqstr_wakeup(void)
{
/* put IRQSTR into ON from STBY mode */
sc_pm_set_resource_power_mode(ipc_handle, SC_R_IRQSTR_SCU2, SC_PM_PW_MODE_ON);
/* disable the irqsteer */
mmio_write_32(IMX_WUP_IRQSTR_BASE, 0x0);
for (int i = 0; i < 16; i++)
mmio_write_32(IMX_WUP_IRQSTR_BASE + 0x4 + 0x4 * i, 0x0);
/* put IRQSTR into OFF mode */
sc_pm_set_resource_power_mode(ipc_handle, SC_R_IRQSTR_SCU2, SC_PM_PW_MODE_OFF);
}
int imx_pwr_domain_on(u_register_t mpidr)
{
int ret = PSCI_E_SUCCESS;
unsigned int cluster_id, cpu_id;
cluster_id = MPIDR_AFFLVL1_VAL(mpidr);
cpu_id = MPIDR_AFFLVL0_VAL(mpidr);
printf("imx_pwr_domain_on cluster_id %d, cpu_id %d\n", cluster_id, cpu_id);
if (cluster_id == 0) {
sc_pm_set_resource_power_mode(ipc_handle, SC_R_A53,
SC_PM_PW_MODE_ON);
if (sc_pm_set_resource_power_mode(ipc_handle, ap_core_index[cpu_id],
SC_PM_PW_MODE_ON) != SC_ERR_NONE) {
ERROR("cluster0 core %d power on failed!\n", cpu_id);
ret = PSCI_E_INTERN_FAIL;
}
if (sc_pm_cpu_start(ipc_handle, ap_core_index[cpu_id],
true, BL31_BASE) != SC_ERR_NONE) {
ERROR("boot cluster0 core %d failed!\n", cpu_id);
ret = PSCI_E_INTERN_FAIL;
}
} else {
sc_pm_set_resource_power_mode(ipc_handle, SC_R_A72,
SC_PM_PW_MODE_ON);
if (sc_pm_set_resource_power_mode(ipc_handle, ap_core_index[cpu_id + 4],
SC_PM_PW_MODE_ON) != SC_ERR_NONE) {
ERROR(" cluster1 core %d power on failed!\n", cpu_id);
ret = PSCI_E_INTERN_FAIL;
}
if (sc_pm_cpu_start(ipc_handle, ap_core_index[cpu_id + 4],
true, BL31_BASE) != SC_ERR_NONE) {
ERROR("boot cluster1 core %d failed!\n", cpu_id);
ret = PSCI_E_INTERN_FAIL;
}
unsigned int cluster_id = MPIDR_AFFLVL1_VAL(mpidr);
unsigned int cpu_id = MPIDR_AFFLVL0_VAL(mpidr);
sc_pm_set_resource_power_mode(ipc_handle, cluster_id == 0 ?
SC_R_A53 : SC_R_A72, SC_PM_PW_MODE_ON);
if (cluster_id == 1)
sc_pm_req_low_power_mode(ipc_handle, SC_R_A72, SC_PM_PW_MODE_ON);
if (sc_pm_set_resource_power_mode(ipc_handle,
ap_core_index[cpu_id + PLATFORM_CLUSTER0_CORE_COUNT * cluster_id],
SC_PM_PW_MODE_ON) != SC_ERR_NONE) {
ERROR("core %d power on failed!\n", cpu_id + PLATFORM_CLUSTER0_CORE_COUNT * cluster_id);
ret = PSCI_E_INTERN_FAIL;
}
if (sc_pm_cpu_start(ipc_handle,
ap_core_index[cpu_id + PLATFORM_CLUSTER0_CORE_COUNT * cluster_id],
true, BL31_BASE) != SC_ERR_NONE) {
ERROR("boot core %d failed!\n", cpu_id + PLATFORM_CLUSTER0_CORE_COUNT * cluster_id);
ret = PSCI_E_INTERN_FAIL;
}
return ret;
......@@ -91,11 +119,14 @@ void imx_pwr_domain_off(const psci_power_state_t *target_state)
plat_gic_cpuif_disable();
sc_pm_req_cpu_low_power_mode(ipc_handle,
ap_core_index[cpu_id + cluster_id * 4],
SC_PM_PW_MODE_OFF,
SC_PM_WAKE_SRC_NONE);
if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE)
cci_disable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(mpidr));
ap_core_index[cpu_id + PLATFORM_CLUSTER0_CORE_COUNT * cluster_id],
SC_PM_PW_MODE_OFF, SC_PM_WAKE_SRC_NONE);
if (is_local_state_off(CLUSTER_PWR_STATE(target_state))) {
cci_disable_snoop_dvm_reqs(cluster_id);
if (cluster_id == 1)
sc_pm_req_low_power_mode(ipc_handle, SC_R_A72, SC_PM_PW_MODE_OFF);
}
printf("turn off cluster:%d core:%d\n", cluster_id, cpu_id);
}
......@@ -105,24 +136,148 @@ void imx_domain_suspend(const psci_power_state_t *target_state)
unsigned int cluster_id = MPIDR_AFFLVL1_VAL(mpidr);
unsigned int cpu_id = MPIDR_AFFLVL0_VAL(mpidr);
plat_gic_cpuif_disable();
if (is_local_state_off(CORE_PWR_STATE(target_state))) {
plat_gic_cpuif_disable();
sc_pm_set_cpu_resume(ipc_handle,
ap_core_index[cpu_id + PLATFORM_CLUSTER0_CORE_COUNT * cluster_id],
true, BL31_BASE);
sc_pm_req_cpu_low_power_mode(ipc_handle,
ap_core_index[cpu_id + PLATFORM_CLUSTER0_CORE_COUNT * cluster_id],
SC_PM_PW_MODE_OFF, SC_PM_WAKE_SRC_GIC);
} else {
dsb();
write_scr_el3(read_scr_el3() | SCR_FIQ_BIT);
isb();
}
cci_disable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(mpidr));
if (is_local_state_off(CLUSTER_PWR_STATE(target_state))) {
cci_disable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(mpidr));
if (cluster_id == 1)
sc_pm_req_low_power_mode(ipc_handle, SC_R_A72, SC_PM_PW_MODE_OFF);
}
sc_pm_set_cpu_resume_addr(ipc_handle,
ap_core_index[cpu_id + cluster_id * 4], BL31_BASE);
sc_pm_req_cpu_low_power_mode(ipc_handle,
ap_core_index[cpu_id + cluster_id * 4],
SC_PM_PW_MODE_OFF, SC_PM_WAKE_SRC_GIC);
if (is_local_state_retn(SYSTEM_PWR_STATE(target_state))) {
plat_gic_cpuif_disable();
/* save gic context */
plat_gic_save(cpu_id, &imx_gicv3_ctx);
/* enable the irqsteer for wakeup */
imx_enable_irqstr_wakeup();
cci_disable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(mpidr));
/* Put GIC in LP mode. */
sc_pm_set_resource_power_mode(ipc_handle, SC_R_GIC, SC_PM_PW_MODE_OFF);
/* Save GPT clock and registers, then turn off its power */
gpt_lpcg = mmio_read_32(IMX_GPT_LPCG_BASE);
gpt_reg[0] = mmio_read_32(IMX_GPT_BASE);
gpt_reg[1] = mmio_read_32(IMX_GPT_BASE + 0x4);
sc_pm_set_resource_power_mode(ipc_handle, SC_R_GPT_0, SC_PM_PW_MODE_OFF);
sc_pm_req_low_power_mode(ipc_handle, SC_R_A53, SC_PM_PW_MODE_OFF);
sc_pm_req_low_power_mode(ipc_handle, SC_R_A72, SC_PM_PW_MODE_OFF);
sc_pm_req_low_power_mode(ipc_handle, SC_R_CCI, SC_PM_PW_MODE_OFF);
sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A53, SC_PM_SYS_IF_DDR,
SC_PM_PW_MODE_ON, SC_PM_PW_MODE_OFF);
sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A72, SC_PM_SYS_IF_DDR,
SC_PM_PW_MODE_ON, SC_PM_PW_MODE_OFF);
sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A53, SC_PM_SYS_IF_MU,
SC_PM_PW_MODE_ON, SC_PM_PW_MODE_OFF);
sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A72, SC_PM_SYS_IF_MU,
SC_PM_PW_MODE_ON, SC_PM_PW_MODE_OFF);
sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A53, SC_PM_SYS_IF_INTERCONNECT,
SC_PM_PW_MODE_ON, SC_PM_PW_MODE_OFF);
sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A72, SC_PM_SYS_IF_INTERCONNECT,
SC_PM_PW_MODE_ON, SC_PM_PW_MODE_OFF);
sc_pm_req_low_power_mode(ipc_handle, SC_R_CCI, SC_PM_PW_MODE_OFF);
sc_pm_set_cpu_resume(ipc_handle,
ap_core_index[cpu_id + PLATFORM_CLUSTER0_CORE_COUNT * cluster_id],
true, BL31_BASE);
if (imx_is_wakeup_src_irqsteer())
sc_pm_req_cpu_low_power_mode(ipc_handle,
ap_core_index[cpu_id + PLATFORM_CLUSTER0_CORE_COUNT * cluster_id],
SC_PM_PW_MODE_OFF, SC_PM_WAKE_SRC_IRQSTEER);
else
sc_pm_req_cpu_low_power_mode(ipc_handle,
ap_core_index[cpu_id + PLATFORM_CLUSTER0_CORE_COUNT * cluster_id],
SC_PM_PW_MODE_OFF, SC_PM_WAKE_SRC_SCU);
}
}
void imx_domain_suspend_finish(const psci_power_state_t *target_state)
{
u_register_t mpidr = read_mpidr_el1();
unsigned int cluster_id = MPIDR_AFFLVL1_VAL(mpidr);
unsigned int cpu_id = MPIDR_AFFLVL0_VAL(mpidr);
cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(mpidr));
/* check the system level status */
if (is_local_state_retn(SYSTEM_PWR_STATE(target_state))) {
MU_Resume(SC_IPC_BASE);
plat_gic_cpuif_enable();
sc_pm_req_cpu_low_power_mode(ipc_handle,
ap_core_index[cpu_id + PLATFORM_CLUSTER0_CORE_COUNT * cluster_id],
SC_PM_PW_MODE_ON, SC_PM_WAKE_SRC_GIC);
/* Put GIC/IRQSTR back to high power mode. */
sc_pm_set_resource_power_mode(ipc_handle, SC_R_GIC, SC_PM_PW_MODE_ON);
/* Turn GPT power and restore its clock and registers */
sc_pm_set_resource_power_mode(ipc_handle, SC_R_GPT_0, SC_PM_PW_MODE_ON);
sc_pm_clock_enable(ipc_handle, SC_R_GPT_0, SC_PM_CLK_PER, true, 0);
mmio_write_32(IMX_GPT_BASE, gpt_reg[0]);
mmio_write_32(IMX_GPT_BASE + 0x4, gpt_reg[1]);
mmio_write_32(IMX_GPT_LPCG_BASE, gpt_lpcg);
sc_pm_req_low_power_mode(ipc_handle, SC_R_A53, SC_PM_PW_MODE_ON);
sc_pm_req_low_power_mode(ipc_handle, SC_R_A72, SC_PM_PW_MODE_ON);
sc_pm_req_low_power_mode(ipc_handle, SC_R_CCI, SC_PM_PW_MODE_ON);
sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A53, SC_PM_SYS_IF_DDR,
SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON);
sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A72, SC_PM_SYS_IF_DDR,
SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON);
sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A53, SC_PM_SYS_IF_MU,
SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON);
sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A72, SC_PM_SYS_IF_MU,
SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON);
sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A53, SC_PM_SYS_IF_INTERCONNECT,
SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON);
sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A72, SC_PM_SYS_IF_INTERCONNECT,
SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON);
sc_pm_req_low_power_mode(ipc_handle, SC_R_CCI, SC_PM_PW_MODE_ON);
cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(mpidr));
/* restore gic context */
plat_gic_restore(cpu_id, &imx_gicv3_ctx);
/* disable the irqsteer wakeup */
imx_disable_irqstr_wakeup();
plat_gic_cpuif_enable();
}
/* check the cluster level power status */
if (is_local_state_off(CLUSTER_PWR_STATE(target_state))) {
cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(mpidr));
if (cluster_id == 1)
sc_pm_req_low_power_mode(ipc_handle, SC_R_A72, SC_PM_PW_MODE_ON);
}
/* check the core level power status */
if (is_local_state_off(CORE_PWR_STATE(target_state))) {
sc_pm_set_cpu_resume(ipc_handle,
ap_core_index[cpu_id + PLATFORM_CLUSTER0_CORE_COUNT * cluster_id],
false, BL31_BASE);
sc_pm_req_cpu_low_power_mode(ipc_handle,
ap_core_index[cpu_id + PLATFORM_CLUSTER0_CORE_COUNT * cluster_id],
SC_PM_PW_MODE_ON, SC_PM_WAKE_SRC_GIC);
plat_gic_cpuif_enable();
} else {
write_scr_el3(read_scr_el3() & (~SCR_FIQ_BIT));
isb();
}
}
int imx_validate_ns_entrypoint(uintptr_t ns_entrypoint)
......@@ -149,26 +304,23 @@ int plat_setup_psci_ops(uintptr_t sec_entrypoint,
imx_mailbox_init(sec_entrypoint);
*psci_ops = &imx_plat_psci_ops;
/* Request low power mode for cluster/cci, only need to do once */
sc_pm_req_low_power_mode(ipc_handle, SC_R_A72, SC_PM_PW_MODE_OFF);
sc_pm_req_low_power_mode(ipc_handle, SC_R_A53, SC_PM_PW_MODE_OFF);
sc_pm_req_low_power_mode(ipc_handle, SC_R_CCI, SC_PM_PW_MODE_OFF);
/* Request RUN and LP modes for DDR, system interconnect etc. */
sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A53,
SC_PM_SYS_IF_DDR, SC_PM_PW_MODE_ON, SC_PM_PW_MODE_STBY);
sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A72,
SC_PM_SYS_IF_DDR, SC_PM_PW_MODE_ON, SC_PM_PW_MODE_STBY);
sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A53,
SC_PM_SYS_IF_MU, SC_PM_PW_MODE_ON, SC_PM_PW_MODE_STBY);
sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A72,
SC_PM_SYS_IF_MU, SC_PM_PW_MODE_ON, SC_PM_PW_MODE_STBY);
sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A53,
SC_PM_SYS_IF_INTERCONNECT, SC_PM_PW_MODE_ON,
SC_PM_PW_MODE_STBY);
sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A72,
SC_PM_SYS_IF_INTERCONNECT, SC_PM_PW_MODE_ON,
SC_PM_PW_MODE_STBY);
/* make sure system sources power ON in low power mode by default */
sc_pm_req_low_power_mode(ipc_handle, SC_R_A53, SC_PM_PW_MODE_ON);
sc_pm_req_low_power_mode(ipc_handle, SC_R_A72, SC_PM_PW_MODE_ON);
sc_pm_req_low_power_mode(ipc_handle, SC_R_CCI, SC_PM_PW_MODE_ON);
sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A53, SC_PM_SYS_IF_DDR,
SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON);
sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A72, SC_PM_SYS_IF_DDR,
SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON);
sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A53, SC_PM_SYS_IF_MU,
SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON);
sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A72, SC_PM_SYS_IF_MU,
SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON);
sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A53, SC_PM_SYS_IF_INTERCONNECT,
SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON);
sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A72, SC_PM_SYS_IF_INTERCONNECT,
SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON);
return 0;
}
......@@ -36,22 +36,22 @@
#define BL31_LIMIT 0x80020000
#define PLAT_GICD_BASE 0x51a00000
#define PLAT_GICD_SIZE 0x10000
#define PLAT_GICR_BASE 0x51b00000
#define PLAT_GICR_SIZE 0xc0000
#define PLAT_CCI_BASE 0x52090000
#define PLAT_CCI_SIZE 0x10000
#define CLUSTER0_CCI_SLVAE_IFACE 3
#define CLUSTER1_CCI_SLVAE_IFACE 4
#define IMX_BOOT_UART_BASE 0x5a060000
#define IMX_BOOT_UART_SIZE 0x1000
#define IMX_BOOT_UART_BAUDRATE 115200
#define IMX_BOOT_UART_CLK_IN_HZ 24000000
#define PLAT_CRASH_UART_BASE IMX_BOOT_UART_BASE
#define PLAT__CRASH_UART_CLK_IN_HZ 24000000
#define IMX_CONSOLE_BAUDRATE 115200
#define SC_IPC_BASE 0x5d1b0000
#define SC_IPC_SIZE 0x10000
#define IMX_GPT_LPCG_BASE 0x5d540000
#define IMX_GPT_BASE 0x5d140000
#define IMX_WUP_IRQSTR_BASE 0x51090000
#define IMX_REG_BASE 0x50000000
#define IMX_REG_SIZE 0x10000000
#define COUNTER_FREQUENCY 8000000 /* 8MHz */
......
......@@ -19,12 +19,14 @@ sc_rsrc_t secure_rsrcs[] = {
SC_R_GIC_SMMU,
SC_R_CCI,
SC_R_SYSTEM,
SC_R_IRQSTR_SCU2
SC_R_IRQSTR_SCU2,
SC_R_GPT_0
};
/* resources that have register access for non-secure domain */
sc_rsrc_t ns_access_allowed[] = {
SC_R_GIC,
SC_R_GIC_SMMU,
SC_R_CCI
SC_R_CCI,
SC_R_GPT_0
};
......@@ -44,10 +44,7 @@ static entry_point_info_t bl33_image_ep_info;
(SC_PAD_28FDSOI_PS_PD << PADRING_PULL_SHIFT))
static const mmap_region_t imx_mmap[] = {
MAP_REGION_FLAT(IMX_BOOT_UART_BASE, IMX_BOOT_UART_SIZE, MT_DEVICE | MT_RW),
MAP_REGION_FLAT(SC_IPC_BASE, SC_IPC_SIZE, MT_DEVICE | MT_RW),
MAP_REGION_FLAT(PLAT_GICD_BASE, PLAT_GICD_SIZE, MT_DEVICE | MT_RW),
MAP_REGION_FLAT(PLAT_GICR_BASE, PLAT_GICR_SIZE, MT_DEVICE | MT_RW),
MAP_REGION_FLAT(IMX_REG_BASE, IMX_REG_SIZE, MT_DEVICE | MT_RW),
{0}
};
......@@ -281,6 +278,11 @@ void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
/* Turn on MU1 for non-secure OS/Hypervisor */
sc_pm_set_resource_power_mode(ipc_handle, SC_R_MU_1A, SC_PM_PW_MODE_ON);
/* Turn on GPT_0's power & clock for non-secure OS/Hypervisor */
sc_pm_set_resource_power_mode(ipc_handle, SC_R_GPT_0, SC_PM_PW_MODE_ON);
sc_pm_clock_enable(ipc_handle, SC_R_GPT_0, SC_PM_CLK_PER, true, 0);
mmio_write_32(IMX_GPT0_LPCG_BASE, mmio_read_32(IMX_GPT0_LPCG_BASE) | (1 << 25));
/*
* create new partition for non-secure OS/Hypervisor
* uses global structs defined in sec_rsrc.h
......
......@@ -16,10 +16,52 @@
#include <plat_imx8.h>
#include <sci/sci.h>
#include "../../common/sci/imx8_mu.h"
const static int ap_core_index[PLATFORM_CORE_COUNT] = {
SC_R_A35_0, SC_R_A35_1, SC_R_A35_2, SC_R_A35_3
};
/* save gic dist/redist context when GIC is power down */
static struct plat_gic_ctx imx_gicv3_ctx;
static unsigned int gpt_lpcg, gpt_reg[2];
static void imx_enable_irqstr_wakeup(void)
{
uint32_t irq_mask;
gicv3_dist_ctx_t *dist_ctx = &imx_gicv3_ctx.dist_ctx;
/* put IRQSTR into ON mode */
sc_pm_set_resource_power_mode(ipc_handle, SC_R_IRQSTR_SCU2, SC_PM_PW_MODE_ON);
/* enable the irqsteer to handle wakeup irq */
mmio_write_32(IMX_WUP_IRQSTR_BASE, 0x1);
for (int i = 0; i < 15; i++) {
irq_mask = dist_ctx->gicd_isenabler[i];
mmio_write_32(IMX_WUP_IRQSTR_BASE + 0x3c - 0x4 * i, irq_mask);
}
/* set IRQSTR low power mode */
if (imx_is_wakeup_src_irqsteer())
sc_pm_set_resource_power_mode(ipc_handle, SC_R_IRQSTR_SCU2, SC_PM_PW_MODE_STBY);
else
sc_pm_set_resource_power_mode(ipc_handle, SC_R_IRQSTR_SCU2, SC_PM_PW_MODE_OFF);
}
static void imx_disable_irqstr_wakeup(void)
{
/* Put IRQSTEER back to ON mode */
sc_pm_set_resource_power_mode(ipc_handle, SC_R_IRQSTR_SCU2, SC_PM_PW_MODE_ON);
/* disable the irqsteer */
mmio_write_32(IMX_WUP_IRQSTR_BASE, 0x0);
for (int i = 0; i < 16; i++)
mmio_write_32(IMX_WUP_IRQSTR_BASE + 0x4 + 0x4 * i, 0x0);
/* Put IRQSTEER into OFF mode */
sc_pm_set_resource_power_mode(ipc_handle, SC_R_IRQSTR_SCU2, SC_PM_PW_MODE_OFF);
}
int imx_pwr_domain_on(u_register_t mpidr)
{
int ret = PSCI_E_SUCCESS;
......@@ -71,11 +113,52 @@ void imx_domain_suspend(const psci_power_state_t *target_state)
u_register_t mpidr = read_mpidr_el1();
unsigned int cpu_id = MPIDR_AFFLVL0_VAL(mpidr);
plat_gic_cpuif_disable();
if (is_local_state_off(target_state->pwr_domain_state[MPIDR_AFFLVL0])) {
plat_gic_cpuif_disable();
sc_pm_set_cpu_resume(ipc_handle, ap_core_index[cpu_id], true, BL31_BASE);
sc_pm_req_cpu_low_power_mode(ipc_handle, ap_core_index[cpu_id],
SC_PM_PW_MODE_OFF, SC_PM_WAKE_SRC_GIC);
} else {
dsb();
write_scr_el3(read_scr_el3() | SCR_FIQ_BIT);
isb();
}
sc_pm_set_cpu_resume_addr(ipc_handle, ap_core_index[cpu_id], BL31_BASE);
sc_pm_req_cpu_low_power_mode(ipc_handle, ap_core_index[cpu_id],
SC_PM_PW_MODE_OFF, SC_PM_WAKE_SRC_GIC);
if (is_local_state_off(target_state->pwr_domain_state[MPIDR_AFFLVL1]))
sc_pm_req_low_power_mode(ipc_handle, SC_R_A35, SC_PM_PW_MODE_OFF);
if (is_local_state_retn(target_state->pwr_domain_state[PLAT_MAX_PWR_LVL])) {
plat_gic_cpuif_disable();
/* save gic context */
plat_gic_save(cpu_id, &imx_gicv3_ctx);
/* enable the irqsteer for wakeup */
imx_enable_irqstr_wakeup();
/* Save GPT clock and registers, then turn off its power */
gpt_lpcg = mmio_read_32(IMX_GPT0_LPCG_BASE);
gpt_reg[0] = mmio_read_32(IMX_GPT0_BASE);
gpt_reg[1] = mmio_read_32(IMX_GPT0_BASE + 0x4);
sc_pm_set_resource_power_mode(ipc_handle, SC_R_GPT_0, SC_PM_PW_MODE_OFF);
sc_pm_req_low_power_mode(ipc_handle, SC_R_A35, SC_PM_PW_MODE_OFF);
sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A35, SC_PM_SYS_IF_DDR,
SC_PM_PW_MODE_ON, SC_PM_PW_MODE_OFF);
sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A35, SC_PM_SYS_IF_MU,
SC_PM_PW_MODE_ON, SC_PM_PW_MODE_OFF);
sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A35, SC_PM_SYS_IF_INTERCONNECT,
SC_PM_PW_MODE_ON, SC_PM_PW_MODE_OFF);
/* Put GIC in OFF mode. */
sc_pm_set_resource_power_mode(ipc_handle, SC_R_GIC, SC_PM_PW_MODE_OFF);
sc_pm_set_cpu_resume(ipc_handle, ap_core_index[cpu_id], true, BL31_BASE);
if (imx_is_wakeup_src_irqsteer())
sc_pm_req_cpu_low_power_mode(ipc_handle, ap_core_index[cpu_id],
SC_PM_PW_MODE_OFF, SC_PM_WAKE_SRC_IRQSTEER);
else
sc_pm_req_cpu_low_power_mode(ipc_handle, ap_core_index[cpu_id],
SC_PM_PW_MODE_OFF, SC_PM_WAKE_SRC_SCU);
}
}
void imx_domain_suspend_finish(const psci_power_state_t *target_state)
......@@ -83,10 +166,51 @@ void imx_domain_suspend_finish(const psci_power_state_t *target_state)
u_register_t mpidr = read_mpidr_el1();
unsigned int cpu_id = MPIDR_AFFLVL0_VAL(mpidr);
sc_pm_req_low_power_mode(ipc_handle, ap_core_index[cpu_id],
SC_PM_PW_MODE_ON);
if (is_local_state_retn(target_state->pwr_domain_state[PLAT_MAX_PWR_LVL])) {
MU_Resume(SC_IPC_BASE);
plat_gic_cpuif_enable();
sc_pm_req_low_power_mode(ipc_handle, ap_core_index[cpu_id], SC_PM_PW_MODE_ON);
sc_pm_req_cpu_low_power_mode(ipc_handle, ap_core_index[cpu_id],
SC_PM_PW_MODE_ON, SC_PM_WAKE_SRC_GIC);
/* Put GIC back to high power mode. */
sc_pm_set_resource_power_mode(ipc_handle, SC_R_GIC, SC_PM_PW_MODE_ON);
/* restore gic context */
plat_gic_restore(cpu_id, &imx_gicv3_ctx);
/* Turn on GPT power and restore its clock and registers */
sc_pm_set_resource_power_mode(ipc_handle, SC_R_GPT_0, SC_PM_PW_MODE_ON);
sc_pm_clock_enable(ipc_handle, SC_R_GPT_0, SC_PM_CLK_PER, true, 0);
mmio_write_32(IMX_GPT0_BASE, gpt_reg[0]);
mmio_write_32(IMX_GPT0_BASE + 0x4, gpt_reg[1]);
mmio_write_32(IMX_GPT0_LPCG_BASE, gpt_lpcg);
sc_pm_req_low_power_mode(ipc_handle, SC_R_A35, SC_PM_PW_MODE_ON);
sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A35, SC_PM_SYS_IF_DDR,
SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON);
sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A35, SC_PM_SYS_IF_MU,
SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON);
sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A35, SC_PM_SYS_IF_INTERCONNECT,
SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON);
/* disable the irqsteer wakeup */
imx_disable_irqstr_wakeup();
plat_gic_cpuif_enable();
}
if (is_local_state_off(target_state->pwr_domain_state[MPIDR_AFFLVL1]))
sc_pm_req_low_power_mode(ipc_handle, SC_R_A35, SC_PM_PW_MODE_ON);
if (is_local_state_off(target_state->pwr_domain_state[MPIDR_AFFLVL0])) {
sc_pm_req_cpu_low_power_mode(ipc_handle, ap_core_index[cpu_id],
SC_PM_PW_MODE_ON, SC_PM_WAKE_SRC_GIC);
plat_gic_cpuif_enable();
} else {
write_scr_el3(read_scr_el3() & (~SCR_FIQ_BIT));
isb();
}
}
static const plat_psci_ops_t imx_plat_psci_ops = {
......@@ -108,17 +232,15 @@ int plat_setup_psci_ops(uintptr_t sec_entrypoint,
imx_mailbox_init(sec_entrypoint);
*psci_ops = &imx_plat_psci_ops;
/* Request low power mode for A35 cluster, only need to do once */
sc_pm_req_low_power_mode(ipc_handle, SC_R_A35, SC_PM_PW_MODE_OFF);
/* Request RUN and LP modes for DDR, system interconnect etc. */
sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A35,
SC_PM_SYS_IF_DDR, SC_PM_PW_MODE_ON, SC_PM_PW_MODE_STBY);
sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A35,
SC_PM_SYS_IF_MU, SC_PM_PW_MODE_ON, SC_PM_PW_MODE_STBY);
sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A35,
SC_PM_SYS_IF_INTERCONNECT, SC_PM_PW_MODE_ON,
SC_PM_PW_MODE_STBY);
/* make sure system sources power ON in low power mode by default */
sc_pm_req_low_power_mode(ipc_handle, SC_R_A35, SC_PM_PW_MODE_ON);
sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A35, SC_PM_SYS_IF_DDR,
SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON);
sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A35, SC_PM_SYS_IF_MU,
SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON);
sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A35, SC_PM_SYS_IF_INTERCONNECT,
SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON);
return 0;
}
......@@ -37,18 +37,19 @@
#define MAX_MMAP_REGIONS 8
#define PLAT_GICD_BASE 0x51a00000
#define PLAT_GICD_SIZE 0x10000
#define PLAT_GICR_BASE 0x51b00000
#define PLAT_GICR_SIZE 0xc0000
#define IMX_BOOT_UART_BASE 0x5a060000
#define IMX_BOOT_UART_SIZE 0x1000
#define IMX_BOOT_UART_BAUDRATE 115200
#define IMX_BOOT_UART_CLK_IN_HZ 24000000
#define PLAT_CRASH_UART_BASE IMX_BOOT_UART_BASE
#define PLAT__CRASH_UART_CLK_IN_HZ 24000000
#define IMX_CONSOLE_BAUDRATE 115200
#define SC_IPC_BASE 0x5d1b0000
#define SC_IPC_SIZE 0x10000
#define IMX_GPT0_LPCG_BASE 0x5d540000
#define IMX_GPT0_BASE 0x5d140000
#define IMX_WUP_IRQSTR_BASE 0x51090000
#define IMX_REG_BASE 0x50000000
#define IMX_REG_SIZE 0x10000000
#define COUNTER_FREQUENCY 8000000
......
......@@ -14,10 +14,12 @@ sc_rsrc_t secure_rsrcs[] = {
SC_R_A35_3,
SC_R_GIC,
SC_R_SYSTEM,
SC_R_IRQSTR_SCU2
SC_R_IRQSTR_SCU2,
SC_R_GPT_0
};
/* resources that have register access for non-secure domain */
sc_rsrc_t ns_access_allowed[] = {
SC_R_GIC,
SC_R_GPT_0
};
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment