Merge changes I765a7fa0,Ic33f0b6d,I8d1a88c7,I381f96be,I698fa849, ... into integration

* changes:
  fix(cpus): clear CPUPWRCTLR_EL1.CORE_PWRDN_EN_BIT on reset
  chore(docs): drop the "wfi" from `pwr_domain_pwr_down_wfi`
  chore(psci): drop skip_wfi variable
  feat(arm): convert arm platforms to expect a wakeup
  fix(cpus): avoid SME related loss of context on powerdown
  feat(psci): allow cores to wake up from powerdown
  refactor: panic after calling psci_power_down_wfi()
  refactor(cpus): undo errata mitigations
  feat(cpus): add sysreg_bit_toggle
This commit is contained in:
Manish Pandey 2025-02-11 16:52:18 +01:00 committed by TrustedFirmware Code Review
commit fcb80d7d14
65 changed files with 417 additions and 250 deletions

View file

@ -1244,12 +1244,14 @@ $(eval $(call assert_booleans,\
ENCRYPT_BL31 \
ENCRYPT_BL32 \
ERRATA_SPECULATIVE_AT \
ERRATA_SME_POWER_DOWN \
RAS_TRAP_NS_ERR_REC_ACCESS \
COT_DESC_IN_DTB \
USE_SP804_TIMER \
PSA_FWU_SUPPORT \
PSA_FWU_METADATA_FW_STORE_DESC \
ENABLE_MPMM \
FEAT_PABANDON \
ENABLE_MPMM_FCONF \
FEATURE_DETECTION \
TRNG_SUPPORT \
@ -1433,6 +1435,7 @@ $(eval $(call add_defines,\
BL2_INV_DCACHE \
USE_SPINLOCK_CAS \
ERRATA_SPECULATIVE_AT \
ERRATA_SME_POWER_DOWN \
RAS_TRAP_NS_ERR_REC_ACCESS \
COT_DESC_IN_DTB \
USE_SP804_TIMER \
@ -1450,6 +1453,7 @@ $(eval $(call add_defines,\
ENABLE_TRF_FOR_NS \
ENABLE_FEAT_HCX \
ENABLE_MPMM \
FEAT_PABANDON \
ENABLE_MPMM_FCONF \
ENABLE_FEAT_FGT \
ENABLE_FEAT_FGT2 \

View file

@ -1504,6 +1504,19 @@ At runtime the platform hooks for power down are invoked by the PSCI service to
perform platform specific operations during a power down sequence, for example
turning off CCI coherency during a cluster power down.
Newer CPUs include a feature called "powerdown abandon". The feature is based on
the observation that events like GIC wakeups have a high likelihood of happening
while the core is in the middle of its powerdown sequence (at ``wfi``). Older
cores will powerdown and immediately power back up when this happens. To save on
the work and latency involved, the newer cores will "give up" mid way through if
no context has been lost yet. This is possible as the powerdown operation is
lengthy and a large part of it does not lose context.
To cater for this possibility, the powerdown hook will be called a second time
after a wakeup. The expectation is that the first call will operate as before,
while the second call will undo anything the first call did. This should be done
statelessly, for example by toggling the relevant bits.
CPU specific register reporting during crash
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View file

@ -526,6 +526,12 @@ Common build options
power domain dynamic power budgeting and limit the triggering of whole-rail
(i.e. clock chopping) responses to overcurrent conditions. Defaults to ``0``.
- ``FEAT_PABANDON``: Boolean option to enable support for powerdown abandon on
Arm cores that support it (currently Gelas and Travis). Extends the PSCI
implementation to expect waking up after the terminal ``wfi``. Currently,
introduces a performance penalty. Once this is removed, this option will be
removed and the feature will be enabled by default. Defaults to ``0``.
- ``ENABLE_MPMM_FCONF``: Enables configuration of MPMM through FCONF, which
allows platforms with cores supporting MPMM to describe them via the
``HW_CONFIG`` device tree blob. Default is 0.
@ -1206,6 +1212,12 @@ Common build options
implement this workaround due to the behaviour of the errata mentioned
in new SDEN document which will get published soon.
- ``ERRATA_SME_POWER_DOWN``: Boolean option to disable SME (PSTATE.{ZA,SM}=0)
before power down and downgrade a suspend to power down request to a normal
suspend request. This is necessary when software running at lower ELs requests
power down without first clearing these bits. On affected cores, the CME
connected to it will reject its power down request. The default value is 0.
- ``RAS_TRAP_NS_ERR_REC_ACCESS``: This flag enables/disables the SCR_EL3.TERR
bit, to trap access to the RAS ERR and RAS ERX registers from lower ELs.
This flag is disabled by default.

View file

@ -2897,23 +2897,25 @@ allocated in a special area if it cannot fit in the platform's global static
data, for example in DRAM. The Distributor can then be powered down using an
implementation-defined sequence.
plat_psci_ops.pwr_domain_pwr_down_wfi()
plat_psci_ops.pwr_domain_pwr_down()
.......................................
This is an optional function and, if implemented, is expected to perform
platform specific actions including the ``wfi`` invocation which allows the
CPU to powerdown. Since this function is invoked outside the PSCI locks,
the actions performed in this hook must be local to the CPU or the platform
must ensure that races between multiple CPUs cannot occur.
platform specific actions before the CPU is powered down. Since this function is
invoked outside the PSCI locks, the actions performed in this hook must be local
to the CPU or the platform must ensure that races between multiple CPUs cannot
occur.
The ``target_state`` has a similar meaning as described in the ``pwr_domain_off()``
operation and it encodes the platform coordinated target local power states for
the CPU power domain and its parent power domain levels. This function must
not return back to the caller (by calling wfi in an infinite loop to ensure
some CPUs power down mitigations work properly).
the CPU power domain and its parent power domain levels.
If this function is not implemented by the platform, PSCI generic
implementation invokes ``psci_power_down_wfi()`` for power down.
It is preferred that this function returns. The caller will invoke
``psci_power_down_wfi()`` to powerdown the CPU, mitigate any powerdown errata,
and handle any wakeups that may arise. Previously, this function did not return
and instead called ``wfi`` (in an infinite loop) directly. This is still
possible on platforms where this is guaranteed to be terminal, however, it is
strongly discouraged going forward.
plat_psci_ops.pwr_domain_on_finish()
....................................
@ -2965,14 +2967,16 @@ plat_psci_ops.system_off()
This function is called by PSCI implementation in response to a ``SYSTEM_OFF``
call. It performs the platform-specific system poweroff sequence after
notifying the Secure Payload Dispatcher.
notifying the Secure Payload Dispatcher. The caller will call ``wfi`` if this
function returns, similar to `plat_psci_ops.pwr_domain_pwr_down()`_.
plat_psci_ops.system_reset()
............................
This function is called by PSCI implementation in response to a ``SYSTEM_RESET``
call. It performs the platform-specific system reset sequence after
notifying the Secure Payload Dispatcher.
notifying the Secure Payload Dispatcher. The caller will call ``wfi`` if this
function returns, similar to `plat_psci_ops.pwr_domain_pwr_down()`_.
plat_psci_ops.validate_power_state()
....................................
@ -3060,7 +3064,8 @@ reset information. If the ``reset_type`` is not supported, the
function must return ``PSCI_E_NOT_SUPPORTED``. For architectural
resets, all failures must return ``PSCI_E_INVALID_PARAMETERS``
and vendor reset can return other PSCI error codes as defined
in `PSCI`_. On success this function will not return.
in `PSCI`_. If this function returns success, the caller will call
``wfi`` similar to `plat_psci_ops.pwr_domain_pwr_down()`_.
plat_psci_ops.write_mem_protect()
.................................

View file

@ -298,7 +298,7 @@ static void css_raise_pwr_down_interrupt(u_register_t mpidr)
#endif
}
void __dead2 css_scp_system_off(int state)
void css_scp_system_off(int state)
{
int ret;
@ -339,16 +339,13 @@ void __dead2 css_scp_system_off(int state)
}
/* Powerdown of primary core */
psci_pwrdown_cpu(PLAT_MAX_PWR_LVL);
wfi();
ERROR("CSS set power state: operation not handled.\n");
panic();
psci_pwrdown_cpu_start(PLAT_MAX_PWR_LVL);
}
/*
* Helper function to shutdown the system via SCMI.
*/
void __dead2 css_scp_sys_shutdown(void)
void css_scp_sys_shutdown(void)
{
css_scp_system_off(SCMI_SYS_PWR_SHUTDOWN);
}
@ -356,7 +353,7 @@ void __dead2 css_scp_sys_shutdown(void)
/*
* Helper function to reset the system via SCMI.
*/
void __dead2 css_scp_sys_reboot(void)
void css_scp_sys_reboot(void)
{
css_scp_system_off(SCMI_SYS_PWR_COLD_RESET);
}
@ -472,12 +469,8 @@ int css_system_reset2(int is_vendor, int reset_type, u_register_t cookie)
return PSCI_E_INVALID_PARAMS;
css_scp_system_off(SCMI_SYS_PWR_WARM_RESET);
/*
* css_scp_system_off cannot return (it is a __dead function),
* but css_system_reset2 has to return some value, even in
* this case.
*/
return 0;
/* return SUCCESS to finish the powerdown */
return PSCI_E_SUCCESS;
}
#if PROGRAMMABLE_RESET_ADDRESS

View file

@ -117,7 +117,7 @@ int css_scp_get_power_state(u_register_t mpidr, unsigned int power_level)
/*
* Helper function to shutdown the system via SCPI.
*/
void __dead2 css_scp_sys_shutdown(void)
void css_scp_sys_shutdown(void)
{
uint32_t response;
@ -134,15 +134,12 @@ void __dead2 css_scp_sys_shutdown(void)
ERROR("CSS System Off: SCP error %u.\n", response);
panic();
}
wfi();
ERROR("CSS System Off: operation not handled.\n");
panic();
}
/*
* Helper function to reset the system via SCPI.
*/
void __dead2 css_scp_sys_reboot(void)
void css_scp_sys_reboot(void)
{
uint32_t response;
@ -159,7 +156,4 @@ void __dead2 css_scp_sys_reboot(void)
ERROR("CSS System Reset: SCP error %u.\n", response);
panic();
}
wfi();
ERROR("CSS System Reset: operation not handled.\n");
panic();
}

View file

@ -1141,6 +1141,7 @@
******************************************************************************/
#define ID_AA64SMFR0_EL1 S3_0_C0_C4_5
#define SMCR_EL3 S3_6_C1_C2_6
#define SVCR S3_3_C4_C2_2
/* ID_AA64SMFR0_EL1 definitions */
#define ID_AA64SMFR0_EL1_SME_FA64_SHIFT U(63)

View file

@ -572,6 +572,7 @@ DEFINE_RENAME_SYSREG_WRITE_FUNC(zcr_el2, ZCR_EL2)
DEFINE_RENAME_IDREG_READ_FUNC(id_aa64smfr0_el1, ID_AA64SMFR0_EL1)
DEFINE_RENAME_SYSREG_RW_FUNCS(smcr_el3, SMCR_EL3)
DEFINE_RENAME_SYSREG_RW_FUNCS(svcr, SVCR)
DEFINE_RENAME_SYSREG_READ_FUNC(erridr_el1, ERRIDR_EL1)
DEFINE_RENAME_SYSREG_WRITE_FUNC(errselr_el1, ERRSELR_EL1)

View file

@ -22,9 +22,9 @@ void css_scp_suspend(const struct psci_power_state *target_state);
void css_scp_off(const struct psci_power_state *target_state);
void css_scp_on(u_register_t mpidr);
int css_scp_get_power_state(u_register_t mpidr, unsigned int power_level);
void __dead2 css_scp_sys_shutdown(void);
void __dead2 css_scp_sys_reboot(void);
void __dead2 css_scp_system_off(int state);
void css_scp_sys_shutdown(void);
void css_scp_sys_reboot(void);
void css_scp_system_off(int state);
/* API for SCP Boot Image transfer. Return 0 on success, -1 on error */
int css_scp_boot_image_xfer(void *image, unsigned int image_size);

View file

@ -20,10 +20,4 @@
#define CORTEX_ALTO_IMP_CPUPWRCTLR_EL1 S3_0_C15_C2_7
#define CORTEX_ALTO_IMP_CPUPWRCTLR_EL1_CORE_PWRDN_EN_BIT U(1)
/*******************************************************************************
* SME Control registers
******************************************************************************/
#define CORTEX_ALTO_SVCRSM S0_3_C4_C2_3
#define CORTEX_ALTO_SVCRZA S0_3_C4_C4_3
#endif /* CORTEX_ALTO_H */

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2023, Arm Limited. All rights reserved.
* Copyright (c) 2023-2024, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@ -23,10 +23,4 @@
#define CORTEX_GELAS_CPUPWRCTLR_EL1 S3_0_C15_C2_7
#define CORTEX_GELAS_CPUPWRCTLR_EL1_CORE_PWRDN_BIT U(1)
/*******************************************************************************
* SME Control registers
******************************************************************************/
#define CORTEX_GELAS_SVCRSM S0_3_C4_C2_3
#define CORTEX_GELAS_SVCRZA S0_3_C4_C4_3
#endif /* CORTEX_GELAS_H */

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014-2024, Arm Limited and Contributors. All rights reserved.
* Copyright (c) 2014-2025, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@ -402,6 +402,18 @@
msr \_reg, x1
.endm
/*
* Toggle a bit in a system register. Can toggle multiple bits but is limited by
* the way the EOR instrucion encodes them.
*
* see sysreg_bit_set for usage
*/
.macro sysreg_bit_toggle _reg:req, _bit:req, _assert=1
mrs x1, \_reg
eor x1, x1, #\_bit
msr \_reg, x1
.endm
.macro override_vector_table _table:req
adr x1, \_table
msr vbar_el3, x1
@ -451,7 +463,7 @@
* clobbers: x0-x10 (PCS compliant)
*/
.macro apply_erratum _cpu:req, _cve:req, _id:req, _chosen:req, _get_rev=GET_CPU_REV
.if (\_chosen & \_get_rev)
.if (\_chosen && \_get_rev)
mov x9, x30
bl cpu_get_rev_var
mov x10, x0

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2023, Arm Limited. All rights reserved.
* Copyright (c) 2023-2024, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@ -20,10 +20,4 @@
#define TRAVIS_IMP_CPUPWRCTLR_EL1 S3_0_C15_C2_7
#define TRAVIS_IMP_CPUPWRCTLR_EL1_CORE_PWRDN_EN_BIT U(1)
/*******************************************************************************
* SME Control registers
******************************************************************************/
#define TRAVIS_SVCRSM S0_3_C4_C2_3
#define TRAVIS_SVCRZA S0_3_C4_C4_3
#endif /* TRAVIS_H */

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013-2019, Arm Limited and Contributors. All rights reserved.
* Copyright (c) 2013-2024, Arm Limited and Contributors. All rights reserved.
* Copyright (c) 2023, NVIDIA Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
@ -331,10 +331,10 @@ typedef struct plat_psci_ops {
const psci_power_state_t *target_state);
void (*pwr_domain_suspend_finish)(
const psci_power_state_t *target_state);
void __dead2 (*pwr_domain_pwr_down_wfi)(
void (*pwr_domain_pwr_down)(
const psci_power_state_t *target_state);
void __dead2 (*system_off)(void);
void __dead2 (*system_reset)(void);
void (*system_off)(void);
void (*system_reset)(void);
int (*validate_power_state)(unsigned int power_state,
psci_power_state_t *req_state);
int (*validate_ns_entrypoint)(uintptr_t ns_entrypoint);
@ -376,7 +376,7 @@ int psci_features(unsigned int psci_fid);
#if PSCI_OS_INIT_MODE
int psci_set_suspend_mode(unsigned int mode);
#endif
void __dead2 psci_power_down_wfi(void);
void psci_power_down_wfi(void);
void psci_arch_setup(void);
#endif /*__ASSEMBLER__*/

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017-2023, Arm Limited and Contributors. All rights reserved.
* Copyright (c) 2017-2024, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@ -94,6 +94,9 @@ int psci_stop_other_cores(unsigned int this_cpu_idx, unsigned int wait_ms,
bool psci_is_last_on_cpu_safe(unsigned int this_core);
bool psci_are_all_cpus_on_safe(unsigned int this_core);
void psci_pwrdown_cpu(unsigned int power_level);
void psci_pwrdown_cpu_start(unsigned int power_level);
void __dead2 psci_pwrdown_cpu_end_terminal(void);
void psci_pwrdown_cpu_end_wakeup(unsigned int power_level);
void psci_do_manage_extensions(void);
#endif /* __ASSEMBLER__ */

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015-2022, Arm Limited and Contributors. All rights reserved.
* Copyright (c) 2015-2024, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@ -35,8 +35,8 @@ void css_pwr_domain_off(const psci_power_state_t *target_state);
void css_pwr_domain_suspend(const psci_power_state_t *target_state);
void css_pwr_domain_suspend_finish(
const psci_power_state_t *target_state);
void __dead2 css_system_off(void);
void __dead2 css_system_reset(void);
void css_system_off(void);
void css_system_reset(void);
void css_cpu_standby(plat_local_state_t cpu_state);
void css_get_sys_suspend_power_state(psci_power_state_t *req_state);
int css_node_hw_state(u_register_t mpidr, unsigned int power_level);

View file

@ -164,9 +164,11 @@ workaround_reset_end cortex_a710, ERRATUM(2282622)
check_erratum_ls cortex_a710, ERRATUM(2282622), CPU_REV(2, 1)
.global erratum_cortex_a710_2291219_wa
workaround_runtime_start cortex_a710, ERRATUM(2291219), ERRATA_A710_2291219
/* Set bit 36 in ACTLR2_EL1 */
sysreg_bit_set CORTEX_A710_CPUACTLR2_EL1, CORTEX_A710_CPUACTLR2_EL1_BIT_36
/* Set/unset bit 36 in ACTLR2_EL1. The first call will set it, applying
* the workaround. Second call clears it to undo it. */
sysreg_bit_toggle CORTEX_A710_CPUACTLR2_EL1, CORTEX_A710_CPUACTLR2_EL1_BIT_36
workaround_runtime_end cortex_a710, ERRATUM(2291219), NO_ISB
check_erratum_ls cortex_a710, ERRATUM(2291219), CPU_REV(2, 0)

View file

@ -21,26 +21,16 @@
#error "Alto supports only AArch64. Compile with CTX_INCLUDE_AARCH32_REGS=0"
#endif
#if ERRATA_SME_POWER_DOWN == 0
#error "Travis needs ERRATA_SME_POWER_DOWN=1 to powerdown correctly"
#endif
cpu_reset_func_start cortex_alto
/* Disable speculative loads */
msr SSBS, xzr
cpu_reset_func_end cortex_alto
func cortex_alto_core_pwr_dwn
#if ENABLE_SME_FOR_NS
/* ---------------------------------------------------
* Disable SME if enabled and supported
* ---------------------------------------------------
*/
mrs x0, ID_AA64PFR1_EL1
ubfx x0, x0, #ID_AA64PFR1_EL1_SME_SHIFT, \
#ID_AA64PFR1_EL1_SME_WIDTH
cmp x0, #SME_NOT_IMPLEMENTED
b.eq 1f
msr CORTEX_ALTO_SVCRSM, xzr
msr CORTEX_ALTO_SVCRZA, xzr
1:
#endif
/* ---------------------------------------------------
* Enable CPU power down bit in power control register
* ---------------------------------------------------

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2023-2024, Arm Limited. All rights reserved.
* Copyright (c) 2023-2025, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@ -21,12 +21,23 @@
#error "Gelas supports only AArch64. Compile with CTX_INCLUDE_AARCH32_REGS=0"
#endif
#if FEAT_PABANDON == 0
#error "Gelas must be compiled with FEAT_PABANDON enabled"
#endif
#if ERRATA_SME_POWER_DOWN == 0
#error "Gelas needs ERRATA_SME_POWER_DOWN=1 to powerdown correctly"
#endif
cpu_reset_func_start cortex_gelas
/* ----------------------------------------------------
* Disable speculative loads
* ----------------------------------------------------
*/
msr SSBS, xzr
/* model bug: not cleared on reset */
sysreg_bit_clear CORTEX_GELAS_CPUPWRCTLR_EL1, \
CORTEX_GELAS_CPUPWRCTLR_EL1_CORE_PWRDN_BIT
cpu_reset_func_end cortex_gelas
/* ----------------------------------------------------
@ -34,25 +45,12 @@ cpu_reset_func_end cortex_gelas
* ----------------------------------------------------
*/
func cortex_gelas_core_pwr_dwn
#if ENABLE_SME_FOR_NS
/* ---------------------------------------------------
* Disable SME if enabled and supported
* ---------------------------------------------------
*/
mrs x0, ID_AA64PFR1_EL1
ubfx x0, x0, #ID_AA64PFR1_EL1_SME_SHIFT, \
#ID_AA64PFR1_EL1_SME_WIDTH
cmp x0, #SME_NOT_IMPLEMENTED
b.eq 1f
msr CORTEX_GELAS_SVCRSM, xzr
msr CORTEX_GELAS_SVCRZA, xzr
1:
#endif
/* ---------------------------------------------------
* Enable CPU power down bit in power control register
* Flip CPU power down bit in power control register.
* It will be set on powerdown and cleared on wakeup
* ---------------------------------------------------
*/
sysreg_bit_set CORTEX_GELAS_CPUPWRCTLR_EL1, \
sysreg_bit_toggle CORTEX_GELAS_CPUPWRCTLR_EL1, \
CORTEX_GELAS_CPUPWRCTLR_EL1_CORE_PWRDN_BIT
isb
ret

View file

@ -58,8 +58,11 @@ workaround_runtime_end cortex_x3, ERRATUM(2302506), NO_ISB
check_erratum_ls cortex_x3, ERRATUM(2302506), CPU_REV(1, 1)
.global erratum_cortex_x3_2313909_wa
workaround_runtime_start cortex_x3, ERRATUM(2313909), ERRATA_X3_2313909
sysreg_bit_set CORTEX_X3_CPUACTLR2_EL1, CORTEX_X3_CPUACTLR2_EL1_BIT_36
/* Set/unset bit 36 in ACTLR2_EL1. The first call will set it, applying
* the workaround. Second call clears it to undo it. */
sysreg_bit_toggle CORTEX_X3_CPUACTLR2_EL1, CORTEX_X3_CPUACTLR2_EL1_BIT_36
workaround_runtime_end cortex_x3, ERRATUM(2313909), NO_ISB
check_erratum_ls cortex_x3, ERRATUM(2313909), CPU_REV(1, 0)

View file

@ -171,9 +171,11 @@ workaround_reset_end neoverse_n2, ERRATUM(2280757)
check_erratum_ls neoverse_n2, ERRATUM(2280757), CPU_REV(0, 0)
.global erratum_neoverse_n2_2326639_wa
workaround_runtime_start neoverse_n2, ERRATUM(2326639), ERRATA_N2_2326639
/* Set bit 36 in ACTLR2_EL1 */
sysreg_bit_set NEOVERSE_N2_CPUACTLR2_EL1, NEOVERSE_N2_CPUACTLR2_EL1_BIT_36
/* Set/unset bit 36 in ACTLR2_EL1. The first call will set it, applying
* the workaround. Second call clears it to undo it. */
sysreg_bit_toggle NEOVERSE_N2_CPUACTLR2_EL1, NEOVERSE_N2_CPUACTLR2_EL1_BIT_36
workaround_runtime_end neoverse_n2, ERRATUM(2326639)
check_erratum_ls neoverse_n2, ERRATUM(2326639), CPU_REV(0, 0)

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2023-2024, Arm Limited. All rights reserved.
* Copyright (c) 2023-2025, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@ -21,34 +21,32 @@
#error "Travis supports only AArch64. Compile with CTX_INCLUDE_AARCH32_REGS=0"
#endif
#if FEAT_PABANDON == 0
#error "Travis must be compiled with FEAT_PABANDON enabled"
#endif
#if ERRATA_SME_POWER_DOWN == 0
#error "Travis needs ERRATA_SME_POWER_DOWN=1 to powerdown correctly"
#endif
cpu_reset_func_start travis
/* ----------------------------------------------------
* Disable speculative loads
* ----------------------------------------------------
*/
msr SSBS, xzr
/* model bug: not cleared on reset */
sysreg_bit_clear TRAVIS_IMP_CPUPWRCTLR_EL1, \
TRAVIS_IMP_CPUPWRCTLR_EL1_CORE_PWRDN_EN_BIT
cpu_reset_func_end travis
func travis_core_pwr_dwn
#if ENABLE_SME_FOR_NS
/* ---------------------------------------------------
* Disable SME if enabled and supported
* ---------------------------------------------------
*/
mrs x0, ID_AA64PFR1_EL1
ubfx x0, x0, #ID_AA64PFR1_EL1_SME_SHIFT, \
#ID_AA64PFR1_EL1_SME_WIDTH
cmp x0, #SME_NOT_IMPLEMENTED
b.eq 1f
msr TRAVIS_SVCRSM, xzr
msr TRAVIS_SVCRZA, xzr
1:
#endif
/* ---------------------------------------------------
* Enable CPU power down bit in power control register
* Flip CPU power down bit in power control register.
* It will be set on powerdown and cleared on wakeup
* ---------------------------------------------------
*/
sysreg_bit_set TRAVIS_IMP_CPUPWRCTLR_EL1, \
sysreg_bit_toggle TRAVIS_IMP_CPUPWRCTLR_EL1, \
TRAVIS_IMP_CPUPWRCTLR_EL1_CORE_PWRDN_EN_BIT
isb
ret

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014-2024, Arm Limited and Contributors. All rights reserved.
* Copyright (c) 2014-2025, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@ -118,17 +118,24 @@ func psci_do_pwrup_cache_maintenance
endfunc psci_do_pwrup_cache_maintenance
/* -----------------------------------------------------------------------
* void psci_power_down_wfi(void);
* This function is called to indicate to the power controller that it
* is safe to power down this cpu. It should not exit the wfi and will
* be released from reset upon power up.
* void psci_power_down_wfi(void); This function is called to indicate to the
* power controller that it is safe to power down this cpu. It may exit if the
* request was denied and reset did not occur
* -----------------------------------------------------------------------
*/
func psci_power_down_wfi
apply_erratum cortex_a510, ERRATUM(2684597), ERRATA_A510_2684597
dsb sy // ensure write buffer empty
1:
wfi
b 1b
/*
* in case the WFI wasn't terminal, we have to undo errata mitigations.
* These will be smart enough to handle being called the same way
*/
apply_erratum cortex_a710, ERRATUM(2291219), ERRATA_A710_2291219
apply_erratum cortex_x3, ERRATUM(2313909), ERRATA_X3_2313909, NO_GET_CPU_REV
apply_erratum neoverse_n2, ERRATUM(2326639), ERRATA_N2_2326639, NO_GET_CPU_REV
ret
endfunc psci_power_down_wfi

View file

@ -1019,8 +1019,12 @@ void psci_warmboot_entrypoint(void)
*/
if (psci_get_aff_info_state() == AFF_STATE_ON_PENDING)
psci_cpu_on_finish(cpu_idx, &state_info);
else
psci_cpu_suspend_to_powerdown_finish(cpu_idx, &state_info);
else {
unsigned int max_off_lvl = psci_find_max_off_lvl(&state_info);
assert(max_off_lvl != PSCI_INVALID_PWR_LVL);
psci_cpu_suspend_to_powerdown_finish(cpu_idx, max_off_lvl, &state_info);
}
/*
* Generic management: Now we just need to retrieve the
@ -1156,7 +1160,7 @@ int psci_secondaries_brought_up(void)
* Initiate power down sequence, by calling power down operations registered for
* this CPU.
******************************************************************************/
void psci_pwrdown_cpu(unsigned int power_level)
void psci_pwrdown_cpu_start(unsigned int power_level)
{
#if ENABLE_RUNTIME_INSTRUMENTATION
@ -1196,6 +1200,72 @@ void psci_pwrdown_cpu(unsigned int power_level)
#endif
}
/*******************************************************************************
* Finish a terminal power down sequence, ending with a wfi. In case of wakeup
* will retry the sleep and panic if it persists.
******************************************************************************/
void __dead2 psci_pwrdown_cpu_end_terminal(void)
{
#if ERRATA_SME_POWER_DOWN
/*
* force SME off to not get power down rejected. Getting here is
* terminal so we don't care if we lose context because of another
* wakeup
*/
if (is_feat_sme_supported()) {
write_svcr(0);
isb();
}
#endif /* ERRATA_SME_POWER_DOWN */
/*
* Execute a wfi which, in most cases, will allow the power controller
* to physically power down this cpu. Under some circumstances that may
* be denied. Hopefully this is transient, retrying a few times should
* power down.
*/
for (int i = 0; i < 32; i++)
psci_power_down_wfi();
/* Wake up wasn't transient. System is probably in a bad state. */
ERROR("Could not power off CPU.\n");
panic();
}
/*******************************************************************************
* Finish a non-terminal power down sequence, ending with a wfi. In case of
* wakeup will unwind any CPU specific actions and return.
******************************************************************************/
void psci_pwrdown_cpu_end_wakeup(unsigned int power_level)
{
/*
* Usually, will be terminal. In some circumstances the powerdown will
* be denied and we'll need to unwind
*/
psci_power_down_wfi();
/*
* Waking up does not require hardware-assisted coherency, but that is
* the case for every core that can wake up. Untangling the cache
* coherency code from powerdown is a non-trivial effort which isn't
* needed for our purposes.
*/
#if !FEAT_PABANDON
ERROR("Systems without FEAT_PABANDON shouldn't wake up.\n");
panic();
#else /* FEAT_PABANDON */
/*
* Begin unwinding. Everything can be shared with CPU_ON and co later,
* except the CPU specific bit. Cores that have hardware-assisted
* coherency don't have much to do so just calling the hook again is
* the simplest way to achieve this
*/
prepare_cpu_pwr_dwn(power_level);
#endif /* FEAT_PABANDON */
}
/*******************************************************************************
* This function invokes the callback 'stop_func()' with the 'mpidr' of each
* online PE. Caller can pass suitable method to stop a remote core.

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013-2022, Arm Limited and Contributors. All rights reserved.
* Copyright (c) 2013-2024, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@ -8,6 +8,7 @@
#include <string.h>
#include <arch.h>
#include <arch_features.h>
#include <arch_helpers.h>
#include <common/debug.h>
#include <lib/pmf/pmf.h>
@ -64,6 +65,19 @@ int psci_cpu_suspend(unsigned int power_state,
plat_local_state_t prev[PLAT_MAX_PWR_LVL];
#endif
#if ERRATA_SME_POWER_DOWN
/*
* If SME isn't off, attempting a real power down will only end up being
* rejected. If we got called with SME on, fall back to a normal
* suspend. We can't force SME off as in the event the power down is
* rejected for another reason (eg GIC) we'd lose the SME context.
*/
if (is_feat_sme_supported() && read_svcr() != 0) {
power_state &= ~(PSTATE_TYPE_MASK << PSTATE_TYPE_SHIFT);
power_state &= ~(PSTATE_PWR_LVL_MASK << PSTATE_PWR_LVL_SHIFT);
}
#endif /* ERRATA_SME_POWER_DOWN */
/* Validate the power_state parameter */
rc = psci_validate_power_state(power_state, &state_info);
if (rc != PSCI_E_SUCCESS) {

View file

@ -93,7 +93,7 @@ int psci_do_cpu_off(unsigned int end_pwrlvl)
*/
if ((psci_spd_pm != NULL) && (psci_spd_pm->svc_off != NULL)) {
rc = psci_spd_pm->svc_off(0);
if (rc != 0)
if (rc != PSCI_E_SUCCESS)
goto exit;
}
@ -115,7 +115,7 @@ int psci_do_cpu_off(unsigned int end_pwrlvl)
/*
* Arch. management. Initiate power down sequence.
*/
psci_pwrdown_cpu(psci_find_max_off_lvl(&state_info));
psci_pwrdown_cpu_start(psci_find_max_off_lvl(&state_info));
/*
* Plat. management: Perform platform specific actions to turn this
@ -153,7 +153,6 @@ exit:
psci_inv_cpu_data(psci_svc_cpu_data.aff_info_state);
#if ENABLE_RUNTIME_INSTRUMENTATION
/*
* Update the timestamp with cache off. We assume this
* timestamp can only be read from the current CPU and the
@ -164,17 +163,12 @@ exit:
RT_INSTR_ENTER_HW_LOW_PWR,
PMF_NO_CACHE_MAINT);
#endif
if (psci_plat_pm_ops->pwr_domain_pwr_down_wfi != NULL) {
/* This function must not return */
psci_plat_pm_ops->pwr_domain_pwr_down_wfi(&state_info);
} else {
/*
* Enter a wfi loop which will allow the power
* controller to physically power down this cpu.
*/
psci_power_down_wfi();
if (psci_plat_pm_ops->pwr_domain_pwr_down != NULL) {
/* This function may not return */
psci_plat_pm_ops->pwr_domain_pwr_down(&state_info);
}
psci_pwrdown_cpu_end_terminal();
}
return rc;

View file

@ -349,7 +349,7 @@ int psci_cpu_suspend_start(unsigned int idx,
psci_power_state_t *state_info,
unsigned int is_power_down_state);
void psci_cpu_suspend_to_powerdown_finish(unsigned int cpu_idx, const psci_power_state_t *state_info);
void psci_cpu_suspend_to_powerdown_finish(unsigned int cpu_idx, unsigned int max_off_lvl, const psci_power_state_t *state_info);
/* Private exported functions from psci_helpers.S */
void psci_do_pwrdown_cache_maintenance(unsigned int pwr_level);

View file

@ -25,8 +25,7 @@
* This function does generic and platform specific operations after a wake-up
* from standby/retention states at multiple power levels.
******************************************************************************/
static void psci_cpu_suspend_to_standby_finish(unsigned int cpu_idx,
unsigned int end_pwrlvl,
static void psci_cpu_suspend_to_standby_finish(unsigned int end_pwrlvl,
psci_power_state_t *state_info)
{
/*
@ -44,11 +43,10 @@ static void psci_cpu_suspend_to_standby_finish(unsigned int cpu_idx,
* operations.
******************************************************************************/
static void psci_suspend_to_pwrdown_start(unsigned int end_pwrlvl,
unsigned int max_off_lvl,
const entry_point_info_t *ep,
const psci_power_state_t *state_info)
{
unsigned int max_off_lvl = psci_find_max_off_lvl(state_info);
PUBLISH_EVENT(psci_suspend_pwrdown_start);
#if PSCI_OS_INIT_MODE
@ -94,10 +92,8 @@ static void psci_suspend_to_pwrdown_start(unsigned int end_pwrlvl,
/*
* Arch. management. Initiate power down sequence.
* TODO : Introduce a mechanism to query the cache level to flush
* and the cpu-ops power down to perform from the platform.
*/
psci_pwrdown_cpu(max_off_lvl);
psci_pwrdown_cpu_start(max_off_lvl);
}
/*******************************************************************************
@ -125,8 +121,12 @@ int psci_cpu_suspend_start(unsigned int idx,
unsigned int is_power_down_state)
{
int rc = PSCI_E_SUCCESS;
bool skip_wfi = false;
unsigned int parent_nodes[PLAT_MAX_PWR_LVL] = {0};
unsigned int max_off_lvl = 0;
#if FEAT_PABANDON
cpu_context_t *ctx = cm_get_context(NON_SECURE);
cpu_context_t old_ctx;
#endif
/*
* This function must only be called on platforms where the
@ -151,7 +151,6 @@ int psci_cpu_suspend_start(unsigned int idx,
* detection that a wake-up interrupt has fired.
*/
if (read_isr_el1() != 0U) {
skip_wfi = true;
goto exit;
}
@ -163,7 +162,6 @@ int psci_cpu_suspend_start(unsigned int idx,
*/
rc = psci_validate_state_coordination(idx, end_pwrlvl, state_info);
if (rc != PSCI_E_SUCCESS) {
skip_wfi = true;
goto exit;
}
} else {
@ -182,7 +180,6 @@ int psci_cpu_suspend_start(unsigned int idx,
if (psci_plat_pm_ops->pwr_domain_validate_suspend != NULL) {
rc = psci_plat_pm_ops->pwr_domain_validate_suspend(state_info);
if (rc != PSCI_E_SUCCESS) {
skip_wfi = true;
goto exit;
}
}
@ -196,8 +193,38 @@ int psci_cpu_suspend_start(unsigned int idx,
psci_stats_update_pwr_down(idx, end_pwrlvl, state_info);
#endif
if (is_power_down_state != 0U)
psci_suspend_to_pwrdown_start(end_pwrlvl, ep, state_info);
if (is_power_down_state != 0U) {
/*
* WHen CTX_INCLUDE_EL2_REGS is usnet, we're probably runnig
* with some SPD that assumes the core is going off so it
* doesn't bother saving NS's context. Do that here until we
* figure out a way to make this coherent.
*/
#if FEAT_PABANDON
#if !CTX_INCLUDE_EL2_REGS
cm_el1_sysregs_context_save(NON_SECURE);
#endif
/*
* when the core wakes it expects its context to already be in
* place so we must overwrite it before powerdown. But if
* powerdown never happens we want the old context. Save it in
* case we wake up. EL2/El1 will not be touched by PSCI so don't
* copy */
memcpy(&ctx->gpregs_ctx, &old_ctx.gpregs_ctx, sizeof(gp_regs_t));
memcpy(&ctx->el3state_ctx, &old_ctx.el3state_ctx, sizeof(el3_state_t));
#if DYNAMIC_WORKAROUND_CVE_2018_3639
memcpy(&ctx->cve_2018_3639_ctx, &old_ctx.cve_2018_3639_ctx, sizeof(cve_2018_3639_t));
#endif
#if ERRATA_SPECULATIVE_AT
memcpy(&ctx->errata_speculative_at_ctx, &old_ctx.errata_speculative_at_ctx, sizeof(errata_speculative_at_t));
#endif
#if CTX_INCLUDE_PAUTH_REGS
memcpy(&ctx->pauth_ctx, &old_ctx.pauth_ctx, sizeof(pauth_t));
#endif
#endif
max_off_lvl = psci_find_max_off_lvl(state_info);
psci_suspend_to_pwrdown_start(end_pwrlvl, max_off_lvl, ep, state_info);
}
/*
* Plat. management: Allow the platform to perform the
@ -212,50 +239,39 @@ int psci_cpu_suspend_start(unsigned int idx,
plat_psci_stat_accounting_start(state_info);
#endif
exit:
/*
* Release the locks corresponding to each power level in the
* reverse order to which they were acquired.
*/
psci_release_pwr_domain_locks(end_pwrlvl, parent_nodes);
if (skip_wfi) {
return rc;
}
if (is_power_down_state != 0U) {
#if ENABLE_RUNTIME_INSTRUMENTATION
/*
* Update the timestamp with cache off. We assume this
* timestamp can only be read from the current CPU and the
* timestamp cache line will be flushed before return to
* normal world on wakeup.
*/
PMF_CAPTURE_TIMESTAMP(rt_instr_svc,
RT_INSTR_ENTER_HW_LOW_PWR,
PMF_NO_CACHE_MAINT);
#endif
/* The function calls below must not return */
if (psci_plat_pm_ops->pwr_domain_pwr_down_wfi != NULL)
psci_plat_pm_ops->pwr_domain_pwr_down_wfi(state_info);
else
psci_power_down_wfi();
}
#if ENABLE_RUNTIME_INSTRUMENTATION
/*
* Update the timestamp with cache off. We assume this
* timestamp can only be read from the current CPU and the
* timestamp cache line will be flushed before return to
* normal world on wakeup.
*/
PMF_CAPTURE_TIMESTAMP(rt_instr_svc,
RT_INSTR_ENTER_HW_LOW_PWR,
PMF_NO_CACHE_MAINT);
#endif
/*
* We will reach here if only retention/standby states have been
* requested at multiple power levels. This means that the cpu
* context will be preserved.
*/
wfi();
if (is_power_down_state != 0U) {
if (psci_plat_pm_ops->pwr_domain_pwr_down != NULL) {
/* This function may not return */
psci_plat_pm_ops->pwr_domain_pwr_down(state_info);
}
psci_pwrdown_cpu_end_wakeup(max_off_lvl);
} else {
/*
* We will reach here if only retention/standby states have been
* requested at multiple power levels. This means that the cpu
* context will be preserved.
*/
wfi();
}
#if ENABLE_RUNTIME_INSTRUMENTATION
PMF_CAPTURE_TIMESTAMP(rt_instr_svc,
@ -277,10 +293,32 @@ exit:
#endif
/*
* After we wake up from context retaining suspend, call the
* context retaining suspend finisher.
* Waking up means we've retained all context. Call the finishers to put
* the system back to a usable state.
*/
psci_cpu_suspend_to_standby_finish(idx, end_pwrlvl, state_info);
if (is_power_down_state != 0U) {
#if FEAT_PABANDON
psci_cpu_suspend_to_powerdown_finish(idx, max_off_lvl, state_info);
/* we overwrote context ourselves, put it back */
memcpy(&ctx->gpregs_ctx, &old_ctx.gpregs_ctx, sizeof(gp_regs_t));
memcpy(&ctx->el3state_ctx, &old_ctx.el3state_ctx, sizeof(el3_state_t));
#if DYNAMIC_WORKAROUND_CVE_2018_3639
memcpy(&ctx->cve_2018_3639_ctx, &old_ctx.cve_2018_3639_ctx, sizeof(cve_2018_3639_t));
#endif
#if ERRATA_SPECULATIVE_AT
memcpy(&ctx->errata_speculative_at_ctx, &old_ctx.errata_speculative_at_ctx, sizeof(errata_speculative_at_t));
#endif
#if CTX_INCLUDE_PAUTH_REGS
memcpy(&ctx->pauth_ctx, &old_ctx.pauth_ctx, sizeof(pauth_t));
#endif
#if !CTX_INCLUDE_EL2_REGS
cm_el1_sysregs_context_restore(NON_SECURE);
#endif
#endif
} else {
psci_cpu_suspend_to_standby_finish(end_pwrlvl, state_info);
}
/*
* Set the requested and target state of this CPU and all the higher
@ -288,6 +326,7 @@ exit:
*/
psci_set_pwr_domains_to_run(idx, end_pwrlvl);
exit:
psci_release_pwr_domain_locks(end_pwrlvl, parent_nodes);
return rc;
@ -298,10 +337,9 @@ exit:
* are called by the common finisher routine in psci_common.c. The `state_info`
* is the psci_power_state from which this CPU has woken up from.
******************************************************************************/
void psci_cpu_suspend_to_powerdown_finish(unsigned int cpu_idx, const psci_power_state_t *state_info)
void psci_cpu_suspend_to_powerdown_finish(unsigned int cpu_idx, unsigned int max_off_lvl, const psci_power_state_t *state_info)
{
unsigned int counter_freq;
unsigned int max_off_lvl;
/* Ensure we have been woken up from a suspended state */
assert((psci_get_aff_info_state() == AFF_STATE_ON) &&
@ -338,8 +376,6 @@ void psci_cpu_suspend_to_powerdown_finish(unsigned int cpu_idx, const psci_power
* error, it's expected to assert within
*/
if ((psci_spd_pm != NULL) && (psci_spd_pm->svc_suspend_finish != NULL)) {
max_off_lvl = psci_find_max_off_lvl(state_info);
assert(max_off_lvl != PSCI_INVALID_PWR_LVL);
psci_spd_pm->svc_suspend_finish(max_off_lvl);
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014-2020, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2014-2024, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@ -30,7 +30,7 @@ void __dead2 psci_system_off(void)
/* Call the platform specific hook */
psci_plat_pm_ops->system_off();
/* This function does not return. We should never get here */
psci_pwrdown_cpu_end_terminal();
}
void __dead2 psci_system_reset(void)
@ -49,7 +49,7 @@ void __dead2 psci_system_reset(void)
/* Call the platform specific hook */
psci_plat_pm_ops->system_reset();
/* This function does not return. We should never get here */
psci_pwrdown_cpu_end_terminal();
}
u_register_t psci_system_reset2(uint32_t reset_type, u_register_t cookie)
@ -79,7 +79,10 @@ u_register_t psci_system_reset2(uint32_t reset_type, u_register_t cookie)
}
console_flush();
return (u_register_t)
psci_plat_pm_ops->system_reset2((int) is_vendor, reset_type,
cookie);
u_register_t ret =
(u_register_t) psci_plat_pm_ops->system_reset2((int) is_vendor, reset_type, cookie);
if (ret != PSCI_E_SUCCESS)
return ret;
psci_pwrdown_cpu_end_terminal();
}

View file

@ -85,6 +85,9 @@ DYN_DISABLE_AUTH := 0
# Enable the Maximum Power Mitigation Mechanism on supporting cores.
ENABLE_MPMM := 0
# Enable support for powerdown abandons
FEAT_PABANDON := 0
# Enable MPMM configuration via FCONF.
ENABLE_MPMM_FCONF := 0
@ -348,6 +351,9 @@ SUPPORT_STACK_MEMTAG := no
# Select workaround for AT speculative behaviour.
ERRATA_SPECULATIVE_AT := 0
# select workaround for SME aborting powerdown
ERRATA_SME_POWER_DOWN := 0
# Trap RAS error record access from Non secure
RAS_TRAP_NS_ERR_REC_ACCESS := 0

View file

@ -49,6 +49,8 @@ static void __dead2 sunxi_system_off(void)
sunxi_cpu_power_off_others();
sunxi_cpu_power_off_self();
psci_power_down_wfi();
/* should never reach here */
panic();
}
static void __dead2 sunxi_system_reset(void)

View file

@ -108,6 +108,8 @@ static void __dead2 sunxi_system_off(void)
}
psci_power_down_wfi();
/* should never reach here */
panic();
}
static void __dead2 sunxi_system_reset(void)
@ -123,6 +125,8 @@ static void __dead2 sunxi_system_reset(void)
}
psci_power_down_wfi();
/* should never reach here */
panic();
}
static int sunxi_system_reset2(int is_vendor, int reset_type, u_register_t cookie)
@ -142,6 +146,8 @@ static int sunxi_system_reset2(int is_vendor, int reset_type, u_register_t cooki
}
psci_power_down_wfi();
/* should never reach here */
panic();
/*
* Should not reach here.

View file

@ -152,7 +152,7 @@ static const plat_psci_ops_t axg_ops = {
.pwr_domain_on = axg_pwr_domain_on,
.pwr_domain_on_finish = axg_pwr_domain_on_finish,
.pwr_domain_off = axg_pwr_domain_off,
.pwr_domain_pwr_down_wfi = axg_pwr_domain_pwr_down_wfi,
.pwr_domain_pwr_down = axg_pwr_domain_pwr_down_wfi,
.system_off = axg_system_off,
.system_reset = axg_system_reset
};

View file

@ -200,7 +200,7 @@ static const plat_psci_ops_t g12a_ops = {
.pwr_domain_on = g12a_pwr_domain_on,
.pwr_domain_on_finish = g12a_pwr_domain_on_finish,
.pwr_domain_off = g12a_pwr_domain_off,
.pwr_domain_pwr_down_wfi = g12a_pwr_domain_pwr_down_wfi,
.pwr_domain_pwr_down = g12a_pwr_domain_pwr_down_wfi,
.system_off = g12a_system_off,
.system_reset = g12a_system_reset
};

View file

@ -176,7 +176,7 @@ static const plat_psci_ops_t gxbb_ops = {
.pwr_domain_on = gxbb_pwr_domain_on,
.pwr_domain_on_finish = gxbb_pwr_domain_on_finish,
.pwr_domain_off = gxbb_pwr_domain_off,
.pwr_domain_pwr_down_wfi = gxbb_pwr_domain_pwr_down_wfi,
.pwr_domain_pwr_down = gxbb_pwr_domain_pwr_down_wfi,
.system_off = gxbb_system_off,
.system_reset = gxbb_system_reset,
};

View file

@ -199,7 +199,7 @@ static const plat_psci_ops_t gxl_ops = {
.pwr_domain_on = gxl_pwr_domain_on,
.pwr_domain_on_finish = gxl_pwr_domain_on_finish,
.pwr_domain_off = gxl_pwr_domain_off,
.pwr_domain_pwr_down_wfi = gxl_pwr_domain_pwr_down_wfi,
.pwr_domain_pwr_down = gxl_pwr_domain_pwr_down_wfi,
.system_off = gxl_system_off,
.system_reset = gxl_system_reset,
};

View file

@ -14,7 +14,7 @@
* platform layer will take care of registering the handlers with PSCI.
******************************************************************************/
static void __dead2 corstone1000_system_reset(void)
static void corstone1000_system_reset(void)
{
uint32_t volatile * const watchdog_ctrl_reg = (uint32_t *) SECURE_WATCHDOG_ADDR_CTRL_REG;
@ -31,9 +31,6 @@ static void __dead2 corstone1000_system_reset(void)
*(watchdog_val_reg) = SECURE_WATCHDOG_COUNTDOWN_VAL;
*watchdog_ctrl_reg = SECURE_WATCHDOG_MASK_ENABLE;
while (1) {
wfi();
}
}
#if defined(CORSTONE1000_FVP_MULTICORE)

View file

@ -295,28 +295,22 @@ static void fvp_pwr_domain_suspend_finish(const psci_power_state_t *target_state
/*******************************************************************************
* FVP handlers to shutdown/reboot the system
******************************************************************************/
static void __dead2 fvp_system_off(void)
static void fvp_system_off(void)
{
/* Write the System Configuration Control Register */
mmio_write_32(V2M_SYSREGS_BASE + V2M_SYS_CFGCTRL,
V2M_CFGCTRL_START |
V2M_CFGCTRL_RW |
V2M_CFGCTRL_FUNC(V2M_FUNC_SHUTDOWN));
wfi();
ERROR("FVP System Off: operation not handled.\n");
panic();
}
static void __dead2 fvp_system_reset(void)
static void fvp_system_reset(void)
{
/* Write the System Configuration Control Register */
mmio_write_32(V2M_SYSREGS_BASE + V2M_SYS_CFGCTRL,
V2M_CFGCTRL_START |
V2M_CFGCTRL_RW |
V2M_CFGCTRL_FUNC(V2M_FUNC_REBOOT));
wfi();
ERROR("FVP System Reset: operation not handled.\n");
panic();
}
static int fvp_node_hw_state(u_register_t target_cpu,

View file

@ -235,6 +235,9 @@ endif
#Build AArch64-only CPUs with no FVP model yet.
ifeq (${BUILD_CPUS_WITH_NO_FVP_MODEL},1)
# travis/gelas need these
FEAT_PABANDON := 1
ERRATA_SME_POWER_DOWN := 1
FVP_CPU_LIBS += lib/cpus/aarch64/neoverse_n3.S \
lib/cpus/aarch64/cortex_gelas.S \
lib/cpus/aarch64/nevis.S \

View file

@ -1,4 +1,4 @@
# Copyright (c) 2021-2024, Arm Limited. All rights reserved.
# Copyright (c) 2021-2025, Arm Limited. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
@ -157,6 +157,9 @@ endif
# CPU libraries for TARGET_PLATFORM=4
ifeq (${TARGET_PLATFORM}, 4)
FEAT_PABANDON := 1
# prevent CME related wakups
ERRATA_SME_POWER_DOWN := 1
TC_CPU_SOURCES += lib/cpus/aarch64/cortex_gelas.S \
lib/cpus/aarch64/nevis.S \
lib/cpus/aarch64/travis.S

View file

@ -217,12 +217,12 @@ void css_pwr_domain_suspend_finish(
/*******************************************************************************
* Handlers to shutdown/reboot the system
******************************************************************************/
void __dead2 css_system_off(void)
void css_system_off(void)
{
css_scp_sys_shutdown();
}
void __dead2 css_system_reset(void)
void css_system_reset(void)
{
css_scp_sys_reboot();
}
@ -364,11 +364,9 @@ int css_reboot_interrupt_handler(uint32_t intr_raw, uint32_t flags,
plat_arm_gic_cpuif_disable();
plat_arm_gic_redistif_off();
psci_pwrdown_cpu(PLAT_MAX_PWR_LVL);
psci_pwrdown_cpu_start(PLAT_MAX_PWR_LVL);
dmbsy();
wfi();
psci_pwrdown_cpu_end_terminal();
return 0;
}

View file

@ -25,7 +25,7 @@ static const plat_psci_ops_t imx_plat_psci_ops = {
.cpu_standby = imx_cpu_standby,
.pwr_domain_suspend = imx_domain_suspend,
.pwr_domain_suspend_finish = imx_domain_suspend_finish,
.pwr_domain_pwr_down_wfi = imx_pwr_domain_pwr_down_wfi,
.pwr_domain_pwr_down = imx_pwr_domain_pwr_down_wfi,
.get_sys_suspend_power_state = imx_get_sys_suspend_power_state,
.system_reset = imx_system_reset,
.system_reset2 = imx_system_reset2,

View file

@ -25,7 +25,7 @@ static const plat_psci_ops_t imx_plat_psci_ops = {
.cpu_standby = imx_cpu_standby,
.pwr_domain_suspend = imx_domain_suspend,
.pwr_domain_suspend_finish = imx_domain_suspend_finish,
.pwr_domain_pwr_down_wfi = imx_pwr_domain_pwr_down_wfi,
.pwr_domain_pwr_down = imx_pwr_domain_pwr_down_wfi,
.get_sys_suspend_power_state = imx_get_sys_suspend_power_state,
.system_reset = imx_system_reset,
.system_off = imx_system_off,

View file

@ -25,7 +25,7 @@ static const plat_psci_ops_t imx_plat_psci_ops = {
.cpu_standby = imx_cpu_standby,
.pwr_domain_suspend = imx_domain_suspend,
.pwr_domain_suspend_finish = imx_domain_suspend_finish,
.pwr_domain_pwr_down_wfi = imx_pwr_domain_pwr_down_wfi,
.pwr_domain_pwr_down = imx_pwr_domain_pwr_down_wfi,
.get_sys_suspend_power_state = imx_get_sys_suspend_power_state,
.system_reset = imx_system_reset,
.system_off = imx_system_off,

View file

@ -137,7 +137,7 @@ static const plat_psci_ops_t imx_plat_psci_ops = {
.cpu_standby = imx_cpu_standby,
.pwr_domain_suspend = imx_domain_suspend,
.pwr_domain_suspend_finish = imx_domain_suspend_finish,
.pwr_domain_pwr_down_wfi = imx_pwr_domain_pwr_down_wfi,
.pwr_domain_pwr_down = imx_pwr_domain_pwr_down_wfi,
.get_sys_suspend_power_state = imx_get_sys_suspend_power_state,
.system_reset = imx_system_reset,
.system_reset2 = imx_system_reset2,

View file

@ -538,7 +538,7 @@ static const plat_psci_ops_t imx_plat_psci_ops = {
.pwr_domain_suspend_finish = imx_domain_suspend_finish,
.get_sys_suspend_power_state = imx_get_sys_suspend_power_state,
.validate_power_state = imx_validate_power_state,
.pwr_domain_pwr_down_wfi = imx8ulp_pwr_domain_pwr_down_wfi,
.pwr_domain_pwr_down = imx8ulp_pwr_domain_pwr_down_wfi,
};
int plat_setup_psci_ops(uintptr_t sec_entrypoint,

View file

@ -845,7 +845,7 @@ const plat_psci_ops_t plat_arm_psci_pm_ops = {
.pwr_domain_on_finish = a8k_pwr_domain_on_finish,
.get_sys_suspend_power_state = a8k_get_sys_suspend_power_state,
.pwr_domain_suspend_finish = a8k_pwr_domain_suspend_finish,
.pwr_domain_pwr_down_wfi = a8k_pwr_domain_pwr_down_wfi,
.pwr_domain_pwr_down = a8k_pwr_domain_pwr_down_wfi,
.system_off = a8k_system_off,
.system_reset = a8k_system_reset,
.validate_power_state = a8k_validate_power_state,

View file

@ -78,7 +78,7 @@ struct plat_pm_pwr_ctrl {
psci_power_state_t *req_state);
void (*get_sys_suspend_power_state)(
psci_power_state_t *req_state);
__dead2 void (*pwr_domain_pwr_down_wfi)(
void (*pwr_domain_pwr_down_wfi)(
const psci_power_state_t *req_state);
};

View file

@ -379,7 +379,7 @@ static void get_sys_suspend_power_state(psci_power_state_t *req_state)
}
#endif
static void __dead2 pwr_domain_pwr_down_wfi(const psci_power_state_t *req_state)
static void pwr_domain_pwr_down_wfi(const psci_power_state_t *req_state)
{
unsigned int cpu = plat_my_core_pos();
int ret = MTK_CPUPM_E_NOT_SUPPORT;
@ -390,6 +390,8 @@ static void __dead2 pwr_domain_pwr_down_wfi(const psci_power_state_t *req_state)
plat_panic_handler();
else
psci_power_down_wfi();
/* should never reach here */
panic();
}
static void pm_smp_init(unsigned int cpu_id, uintptr_t entry_point)

View file

@ -45,8 +45,8 @@ int plat_pm_ops_setup_pwr(struct plat_pm_pwr_ctrl *ops)
mtk_pm_ops.get_sys_suspend_power_state = ops->get_sys_suspend_power_state;
}
if (!mtk_pm_ops.pwr_domain_pwr_down_wfi)
mtk_pm_ops.pwr_domain_pwr_down_wfi = ops->pwr_domain_pwr_down_wfi;
if (!mtk_pm_ops.pwr_domain_pwr_down)
mtk_pm_ops.pwr_domain_pwr_down = ops->pwr_domain_pwr_down_wfi;
mtk_pm_status |= MTK_PM_ST_PWR_READY;
#endif

View file

@ -384,7 +384,7 @@ static const plat_psci_ops_t npcm845x_plat_psci_ops = {
/* For testing purposes only This PSCI states are not supported */
.pwr_domain_off = npcm845x_pwr_domain_off,
.pwr_domain_pwr_down_wfi = npcm845x_pwr_down_wfi,
.pwr_domain_pwr_down = npcm845x_pwr_down_wfi,
};
/* For reference only
@ -400,7 +400,7 @@ static const plat_psci_ops_t npcm845x_plat_psci_ops = {
* const psci_power_state_t *target_state);
* void (*pwr_domain_suspend_finish)(
* const psci_power_state_t *target_state);
* void __dead2 (*pwr_domain_pwr_down_wfi)(
* void __dead2 (*pwr_domain_pwr_down )(
* const psci_power_state_t *target_state);
* void __dead2 (*system_off)(void);
* void __dead2 (*system_reset)(void);

View file

@ -284,7 +284,7 @@ static plat_psci_ops_t tegra_plat_psci_ops = {
.pwr_domain_suspend = tegra_pwr_domain_suspend,
.pwr_domain_on_finish = tegra_pwr_domain_on_finish,
.pwr_domain_suspend_finish = tegra_pwr_domain_suspend_finish,
.pwr_domain_pwr_down_wfi = tegra_pwr_domain_power_down_wfi,
.pwr_domain_pwr_down = tegra_pwr_domain_power_down_wfi,
.system_off = tegra_system_off,
.system_reset = tegra_system_reset,
.validate_power_state = tegra_validate_power_state,

View file

@ -433,7 +433,7 @@ static plat_psci_ops_t _psci_pm_ops = {
.pwr_domain_off = _pwr_domain_off,
#endif
#if (SOC_CORE_OFF || SOC_CORE_PWR_DWN)
.pwr_domain_pwr_down_wfi = _pwr_down_wfi,
.pwr_domain_pwr_down = _pwr_down_wfi,
#endif
#if (SOC_CORE_STANDBY || SOC_CORE_PWR_DWN)
/* cpu_suspend */

View file

@ -218,7 +218,7 @@ static const plat_psci_ops_t plat_qemu_psci_pm_ops = {
.cpu_standby = qemu_cpu_standby,
.pwr_domain_on = qemu_pwr_domain_on,
.pwr_domain_off = qemu_pwr_domain_off,
.pwr_domain_pwr_down_wfi = qemu_pwr_domain_pwr_down_wfi,
.pwr_domain_pwr_down = qemu_pwr_domain_pwr_down_wfi,
.pwr_domain_suspend = qemu_pwr_domain_suspend,
.pwr_domain_on_finish = qemu_pwr_domain_on_finish,
.pwr_domain_suspend_finish = qemu_pwr_domain_suspend_finish,

View file

@ -215,7 +215,7 @@ static const plat_psci_ops_t plat_qemu_psci_pm_ops = {
.cpu_standby = qemu_cpu_standby,
.pwr_domain_on = qemu_pwr_domain_on,
.pwr_domain_off = qemu_pwr_domain_off,
.pwr_domain_pwr_down_wfi = qemu_pwr_domain_pwr_down_wfi,
.pwr_domain_pwr_down = qemu_pwr_domain_pwr_down_wfi,
.pwr_domain_suspend = qemu_pwr_domain_suspend,
.pwr_domain_on_finish = qemu_pwr_domain_on_finish,
.pwr_domain_suspend_finish = qemu_pwr_domain_suspend_finish,

View file

@ -217,6 +217,7 @@ __dead2 void qti_domain_power_down_wfi(const psci_power_state_t *target_state)
/* For now just do WFI - add any target specific handling if needed */
psci_power_down_wfi();
/* We should never reach here */
panic();
}
static __dead2 void assert_ps_hold(void)
@ -277,7 +278,7 @@ const plat_psci_ops_t plat_qti_psci_pm_ops = {
.pwr_domain_off = qti_node_power_off,
.pwr_domain_suspend = qti_node_suspend,
.pwr_domain_suspend_finish = qti_node_suspend_finish,
.pwr_domain_pwr_down_wfi = qti_domain_power_down_wfi,
.pwr_domain_pwr_down = qti_domain_power_down_wfi,
.system_off = qti_system_off,
.system_reset = qti_system_reset,
.get_node_hw_state = NULL,

View file

@ -302,7 +302,7 @@ static const plat_psci_ops_t rcar_plat_psci_ops = {
.system_off = rcar_system_off,
.system_reset = rcar_system_reset,
.validate_power_state = rcar_validate_power_state,
.pwr_domain_pwr_down_wfi = rcar_pwr_domain_pwr_down_wfi,
.pwr_domain_pwr_down = rcar_pwr_domain_pwr_down_wfi,
#if RCAR_SYSTEM_SUSPEND
.get_sys_suspend_power_state = rcar_get_sys_suspend_power_state,
#endif

View file

@ -118,11 +118,15 @@ void __dead2 rockchip_soc_cores_pd_pwr_dn_wfi(
const psci_power_state_t *target_state)
{
psci_power_down_wfi();
/* should never reach here */
panic();
}
void __dead2 rockchip_soc_sys_pd_pwr_dn_wfi(void)
{
psci_power_down_wfi();
/* should never reach here */
panic();
}
/*******************************************************************************
@ -391,7 +395,7 @@ const plat_psci_ops_t plat_rockchip_psci_pm_ops = {
.pwr_domain_suspend = rockchip_pwr_domain_suspend,
.pwr_domain_on_finish = rockchip_pwr_domain_on_finish,
.pwr_domain_suspend_finish = rockchip_pwr_domain_suspend_finish,
.pwr_domain_pwr_down_wfi = rockchip_pd_pwr_down_wfi,
.pwr_domain_pwr_down = rockchip_pd_pwr_down_wfi,
.system_reset = rockchip_system_reset,
.system_off = rockchip_system_poweroff,
.validate_power_state = rockchip_validate_power_state,

View file

@ -1000,6 +1000,8 @@ void __dead2 rockchip_soc_soft_reset(void)
* so we do not hope the core to execute valid codes.
*/
psci_power_down_wfi();
/* should never reach here */
panic();
}
void __dead2 rockchip_soc_system_off(void)
@ -1025,6 +1027,8 @@ void __dead2 rockchip_soc_system_off(void)
* so we do not hope the core to execute valid codes.
*/
psci_power_down_wfi();
/* should never reach here */
panic();
}
void rockchip_plat_mmu_el3(void)

View file

@ -619,6 +619,8 @@ void __dead2 rockchip_soc_sys_pd_pwr_dn_wfi(void)
/* should never reach here */
psci_power_down_wfi();
/* should never reach here */
panic();
}
int rockchip_soc_sys_pwr_dm_suspend(void)

View file

@ -1319,12 +1319,16 @@ void __dead2 rockchip_soc_cores_pd_pwr_dn_wfi(const
psci_power_state_t *target_state)
{
psci_power_down_wfi();
/* should never reach here */
panic();
}
void __dead2 rockchip_soc_sys_pd_pwr_dn_wfi(void)
{
cpus_pd_req_enter_wfi();
psci_power_down_wfi();
/* should never reach here */
panic();
}
void __dead2 rockchip_soc_soft_reset(void)
@ -1352,6 +1356,8 @@ void __dead2 rockchip_soc_soft_reset(void)
* so we do not hope the core to execute valid codes.
*/
psci_power_down_wfi();
/* should never reach here */
panic();
}
void __dead2 rockchip_soc_system_off(void)
@ -1373,6 +1379,8 @@ void __dead2 rockchip_soc_system_off(void)
* so we do not hope the core to execute valid codes.
*/
psci_power_down_wfi();
/* should never reach here */
panic();
}
static void rockchip_pmu_pd_init(void)

View file

@ -272,7 +272,7 @@ static const plat_psci_ops_t plat_rpi3_psci_pm_ops = {
.pwr_domain_off = rpi3_pwr_domain_off,
.pwr_domain_on = rpi3_pwr_domain_on,
.pwr_domain_on_finish = rpi3_pwr_domain_on_finish,
.pwr_domain_pwr_down_wfi = rpi3_pwr_down_wfi,
.pwr_domain_pwr_down = rpi3_pwr_down_wfi,
.system_off = rpi3_system_off,
.system_reset = rpi3_system_reset,
.validate_power_state = rpi3_validate_power_state,

View file

@ -113,7 +113,7 @@ static const struct plat_psci_ops uniphier_psci_ops = {
.pwr_domain_on = uniphier_psci_pwr_domain_on,
.pwr_domain_off = uniphier_psci_pwr_domain_off,
.pwr_domain_on_finish = uniphier_psci_pwr_domain_on_finish,
.pwr_domain_pwr_down_wfi = uniphier_psci_pwr_domain_pwr_down_wfi,
.pwr_domain_pwr_down = uniphier_psci_pwr_domain_pwr_down_wfi,
.system_off = uniphier_psci_system_off,
.system_reset = uniphier_psci_system_reset,
};

View file

@ -215,7 +215,7 @@ static const plat_psci_ops_t stm32_psci_ops = {
.pwr_domain_suspend = stm32_pwr_domain_suspend,
.pwr_domain_on_finish = stm32_pwr_domain_on_finish,
.pwr_domain_suspend_finish = stm32_pwr_domain_suspend_finish,
.pwr_domain_pwr_down_wfi = stm32_pwr_domain_pwr_down_wfi,
.pwr_domain_pwr_down = stm32_pwr_domain_pwr_down_wfi,
.system_off = stm32_system_off,
.system_reset = stm32_system_reset,
.validate_power_state = stm32_validate_power_state,

View file

@ -103,7 +103,7 @@ static const plat_psci_ops_t stm32_psci_ops = {
.pwr_domain_suspend = stm32_pwr_domain_suspend,
.pwr_domain_on_finish = stm32_pwr_domain_on_finish,
.pwr_domain_suspend_finish = stm32_pwr_domain_suspend_finish,
.pwr_domain_pwr_down_wfi = stm32_pwr_domain_pwr_down_wfi,
.pwr_domain_pwr_down = stm32_pwr_domain_pwr_down_wfi,
.system_off = stm32_system_off,
.system_reset = stm32_system_reset,
.validate_power_state = stm32_validate_power_state,