Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
174 changes: 18 additions & 156 deletions soc/nordic/nrf54h/pm_s2ram.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
*/

#include <zephyr/arch/cpu.h>
#include <zephyr/arch/arm/mpu/arm_mpu.h>
#include <zephyr/arch/arm/cortex_m/scb.h>
#include <zephyr/arch/arm/cortex_m/fpu.h>
#include <zephyr/arch/common/pm_s2ram.h>
#include <zephyr/linker/sections.h>
#include <zephyr/sys/util.h>
Expand All @@ -22,115 +25,26 @@
#define SCnSCB_CPPWR_SU10_Pos 20U /*!< CPPWR: SU10 Position */
#define SCnSCB_CPPWR_SU10_Msk (1UL << SCnSCB_CPPWR_SU10_Pos) /*!< CPPWR: SU10 Mask */

/* Currently dynamic regions are only used in case of userspace or stack guard and
* stack guard is not used by default on Cortex-M33 because there is a dedicated
* mechanism for stack overflow detection. Unless those condition change we don't
* need to store MPU content, it can just be reinitialized on resuming.
*/
#define MPU_USE_DYNAMIC_REGIONS IS_ENABLED(CONFIG_USERSPACE) || IS_ENABLED(CONFIG_MPU_STACK_GUARD)

/* TODO: The num-mpu-regions property should be used. Needs to be added to dts bindings. */
#define MPU_MAX_NUM_REGIONS 16

typedef struct {
/* NVIC components stored into RAM. */
uint32_t ISER[NVIC_MEMBER_SIZE(ISER)];
uint32_t ISPR[NVIC_MEMBER_SIZE(ISPR)];
uint8_t IPR[NVIC_MEMBER_SIZE(IPR)];
} _nvic_context_t;

typedef struct {
uint32_t RNR;
uint32_t RBAR[MPU_MAX_NUM_REGIONS];
uint32_t RLAR[MPU_MAX_NUM_REGIONS];
uint32_t MAIR0;
uint32_t MAIR1;
uint32_t CTRL;
} _mpu_context_t;

typedef struct {
uint32_t ICSR;
uint32_t VTOR;
uint32_t AIRCR;
uint32_t SCR;
uint32_t CCR;
uint32_t SHPR[12U];
uint32_t SHCSR;
uint32_t CFSR;
uint32_t HFSR;
uint32_t DFSR;
uint32_t MMFAR;
uint32_t BFAR;
uint32_t AFSR;
uint32_t CPACR;
} _scb_context_t;

#if defined(CONFIG_FPU) && !defined(CONFIG_FPU_SHARING)
typedef struct {
uint32_t FPCCR;
uint32_t FPCAR;
uint32_t FPDSCR;
uint32_t S[32];
} _fpu_context_t;
#endif

struct backup {
_nvic_context_t nvic_context;
_mpu_context_t mpu_context;
_scb_context_t scb_context;
#if defined(CONFIG_ARM_MPU)
struct z_mpu_context_retained mpu_context;
#endif
struct scb_context scb_context;
#if defined(CONFIG_FPU) && !defined(CONFIG_FPU_SHARING)
_fpu_context_t fpu_context;
struct fpu_ctx_full fpu_context;
#endif
};

static __noinit struct backup backup_data;

extern void z_arm_configure_static_mpu_regions(void);
extern int z_arm_mpu_init(void);

/* MPU registers cannot be simply copied because content of RBARx RLARx registers
* depends on region which is selected by RNR register.
*/
static void mpu_save(_mpu_context_t *backup)
{
if (!MPU_USE_DYNAMIC_REGIONS) {
return;
}

backup->RNR = MPU->RNR;

for (uint8_t i = 0; i < MPU_MAX_NUM_REGIONS; i++) {
MPU->RNR = i;
backup->RBAR[i] = MPU->RBAR;
backup->RLAR[i] = MPU->RLAR;
}
backup->MAIR0 = MPU->MAIR0;
backup->MAIR1 = MPU->MAIR1;
backup->CTRL = MPU->CTRL;
}

static void mpu_restore(_mpu_context_t *backup)
{
if (!MPU_USE_DYNAMIC_REGIONS) {
z_arm_mpu_init();
z_arm_configure_static_mpu_regions();
return;
}

uint32_t rnr = backup->RNR;

for (uint8_t i = 0; i < MPU_MAX_NUM_REGIONS; i++) {
MPU->RNR = i;
MPU->RBAR = backup->RBAR[i];
MPU->RLAR = backup->RLAR[i];
}

MPU->MAIR0 = backup->MAIR0;
MPU->MAIR1 = backup->MAIR1;
MPU->RNR = rnr;
MPU->CTRL = backup->CTRL;
}

static void nvic_save(_nvic_context_t *backup)
{
memcpy(backup->ISER, (uint32_t *)NVIC->ISER, sizeof(NVIC->ISER));
Expand All @@ -145,42 +59,6 @@ static void nvic_restore(_nvic_context_t *backup)
memcpy((uint32_t *)NVIC->IPR, backup->IPR, sizeof(NVIC->IPR));
}

static void scb_save(_scb_context_t *backup)
{
backup->ICSR = SCB->ICSR;
backup->VTOR = SCB->VTOR;
backup->AIRCR = SCB->AIRCR;
backup->SCR = SCB->SCR;
backup->CCR = SCB->CCR;
memcpy(backup->SHPR, (uint32_t *)SCB->SHPR, sizeof(SCB->SHPR));
backup->SHCSR = SCB->SHCSR;
backup->CFSR = SCB->CFSR;
backup->HFSR = SCB->HFSR;
backup->DFSR = SCB->DFSR;
backup->MMFAR = SCB->MMFAR;
backup->BFAR = SCB->BFAR;
backup->AFSR = SCB->AFSR;
backup->CPACR = SCB->CPACR;
}

static void scb_restore(_scb_context_t *backup)
{
SCB->ICSR = backup->ICSR;
SCB->VTOR = backup->VTOR;
SCB->AIRCR = backup->AIRCR;
SCB->SCR = backup->SCR;
SCB->CCR = backup->CCR;
memcpy((uint32_t *)SCB->SHPR, backup->SHPR, sizeof(SCB->SHPR));
SCB->SHCSR = backup->SHCSR;
SCB->CFSR = backup->CFSR;
SCB->HFSR = backup->HFSR;
SCB->DFSR = backup->DFSR;
SCB->MMFAR = backup->MMFAR;
SCB->BFAR = backup->BFAR;
SCB->AFSR = backup->AFSR;
SCB->CPACR = backup->CPACR;
}

#if defined(CONFIG_FPU)
static void fpu_power_down(void)
{
Expand All @@ -197,26 +75,6 @@ static void fpu_power_up(void)
__DSB();
__ISB();
}

#if !defined(CONFIG_FPU_SHARING)
static void fpu_save(_fpu_context_t *backup)
{
backup->FPCCR = FPU->FPCCR;
backup->FPCAR = FPU->FPCAR;
backup->FPDSCR = FPU->FPDSCR;

__asm__ volatile("vstmia %0, {s0-s31}\n" : : "r"(backup->S) : "memory");
}

static void fpu_restore(_fpu_context_t *backup)
{
FPU->FPCCR = backup->FPCCR;
FPU->FPCAR = backup->FPCAR;
FPU->FPDSCR = backup->FPDSCR;

__asm__ volatile("vldmia %0, {s0-s31}\n" : : "r"(backup->S) : "memory");
}
#endif /* !defined(CONFIG_FPU_SHARING) */
#endif /* defined(CONFIG_FPU) */

#if DT_NODE_EXISTS(DT_NODELABEL(mcuboot_s2ram)) &&\
Expand All @@ -237,32 +95,36 @@ int soc_s2ram_suspend(pm_s2ram_system_off_fn_t system_off)
int ret;

SET_MCUBOOT_RESUME_MAGIC();
scb_save(&backup_data.scb_context);
z_arm_save_scb_context(&backup_data.scb_context);
#if defined(CONFIG_FPU)
#if !defined(CONFIG_FPU_SHARING)
fpu_save(&backup_data.fpu_context);
z_arm_save_fp_context(&backup_data.fpu_context);
#endif
fpu_power_down();
#endif
nvic_save(&backup_data.nvic_context);
mpu_save(&backup_data.mpu_context);
#if defined(CONFIG_ARM_MPU)
z_arm_save_mpu_context(&backup_data.mpu_context);
#endif
ret = arch_pm_s2ram_suspend(system_off);
/* Cache and FPU are powered down so power up is needed even if s2ram failed. */
nrf_power_up_cache();
#if defined(CONFIG_FPU)
fpu_power_up();
#if !defined(CONFIG_FPU_SHARING)
/* Also the FPU content might be lost. */
fpu_restore(&backup_data.fpu_context);
z_arm_restore_fp_context(&backup_data.fpu_context);
#endif
#endif
if (ret < 0) {
return ret;
}

mpu_restore(&backup_data.mpu_context);
#if defined(CONFIG_ARM_MPU)
z_arm_restore_mpu_context(&backup_data.mpu_context);
#endif
nvic_restore(&backup_data.nvic_context);
scb_restore(&backup_data.scb_context);
z_arm_restore_scb_context(&backup_data.scb_context);

return ret;
}
Expand Down
Loading