Skip to content

Commit 4b42437

Browse files
[nrf fromlist] soc: nordic: nrf54h: s2ram: Add FPU retention
Add FPU power management for suspend to RAM procedures. Add FPU save/restore procedures when `FPU_SHARING` feature is disabled. Upstream PR #: 92264 Signed-off-by: Adam Kondraciuk <adam.kondraciuk@nordicsemi.no>
1 parent eb12c85 commit 4b42437

File tree

1 file changed

+86
-13
lines changed

1 file changed

+86
-13
lines changed

soc/nordic/nrf54h/pm_s2ram.c

Lines changed: 86 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,13 @@
1515

1616
#define NVIC_MEMBER_SIZE(member) ARRAY_SIZE(((NVIC_Type *)0)->member)
1717

18+
/* Coprocessor Power Control Register Definitions */
19+
#define SCnSCB_CPPWR_SU11_Pos 22U /*!< CPPWR: SU11 Position */
20+
#define SCnSCB_CPPWR_SU11_Msk (1UL << SCnSCB_CPPWR_SU11_Pos) /*!< CPPWR: SU11 Mask */
21+
22+
#define SCnSCB_CPPWR_SU10_Pos 20U /*!< CPPWR: SU10 Position */
23+
#define SCnSCB_CPPWR_SU10_Msk (1UL << SCnSCB_CPPWR_SU10_Pos) /*!< CPPWR: SU10 Mask */
24+
1825
/* Currently dynamic regions are only used in case of userspace or stack guard and
1926
* stack guard is not used by default on Cortex-M33 because there is a dedicated
2027
* mechanism for stack overflow detection. Unless those condition change we don't
@@ -55,12 +62,25 @@ typedef struct {
5562
uint32_t MMFAR;
5663
uint32_t BFAR;
5764
uint32_t AFSR;
65+
uint32_t CPACR;
5866
} _scb_context_t;
5967

68+
#if defined(CONFIG_FPU) && !defined(CONFIG_FPU_SHARING)
69+
typedef struct {
70+
uint32_t FPCCR;
71+
uint32_t FPCAR;
72+
uint32_t FPDSCR;
73+
uint32_t S[32];
74+
} _fpu_context_t;
75+
#endif
76+
6077
struct backup {
6178
_nvic_context_t nvic_context;
6279
_mpu_context_t mpu_context;
6380
_scb_context_t scb_context;
81+
#if defined(CONFIG_FPU) && !defined(CONFIG_FPU_SHARING)
82+
_fpu_context_t fpu_context;
83+
#endif
6484
};
6585

6686
static __noinit struct backup backup_data;
@@ -71,7 +91,7 @@ extern int z_arm_mpu_init(void);
7191
/* MPU registers cannot be simply copied because content of RBARx RLARx registers
7292
* depends on region which is selected by RNR register.
7393
*/
74-
static void mpu_suspend(_mpu_context_t *backup)
94+
static void mpu_save(_mpu_context_t *backup)
7595
{
7696
if (!MPU_USE_DYNAMIC_REGIONS) {
7797
return;
@@ -89,7 +109,7 @@ static void mpu_suspend(_mpu_context_t *backup)
89109
backup->CTRL = MPU->CTRL;
90110
}
91111

92-
static void mpu_resume(_mpu_context_t *backup)
112+
static void mpu_restore(_mpu_context_t *backup)
93113
{
94114
if (!MPU_USE_DYNAMIC_REGIONS) {
95115
z_arm_mpu_init();
@@ -111,21 +131,21 @@ static void mpu_resume(_mpu_context_t *backup)
111131
MPU->CTRL = backup->CTRL;
112132
}
113133

114-
static void nvic_suspend(_nvic_context_t *backup)
134+
static void nvic_save(_nvic_context_t *backup)
115135
{
116136
memcpy(backup->ISER, (uint32_t *)NVIC->ISER, sizeof(NVIC->ISER));
117137
memcpy(backup->ISPR, (uint32_t *)NVIC->ISPR, sizeof(NVIC->ISPR));
118138
memcpy(backup->IPR, (uint32_t *)NVIC->IPR, sizeof(NVIC->IPR));
119139
}
120140

121-
static void nvic_resume(_nvic_context_t *backup)
141+
static void nvic_restore(_nvic_context_t *backup)
122142
{
123143
memcpy((uint32_t *)NVIC->ISER, backup->ISER, sizeof(NVIC->ISER));
124144
memcpy((uint32_t *)NVIC->ISPR, backup->ISPR, sizeof(NVIC->ISPR));
125145
memcpy((uint32_t *)NVIC->IPR, backup->IPR, sizeof(NVIC->IPR));
126146
}
127147

128-
static void scb_suspend(_scb_context_t *backup)
148+
static void scb_save(_scb_context_t *backup)
129149
{
130150
backup->ICSR = SCB->ICSR;
131151
backup->VTOR = SCB->VTOR;
@@ -140,9 +160,10 @@ static void scb_suspend(_scb_context_t *backup)
140160
backup->MMFAR = SCB->MMFAR;
141161
backup->BFAR = SCB->BFAR;
142162
backup->AFSR = SCB->AFSR;
163+
backup->CPACR = SCB->CPACR;
143164
}
144165

145-
static void scb_resume(_scb_context_t *backup)
166+
static void scb_restore(_scb_context_t *backup)
146167
{
147168
SCB->ICSR = backup->ICSR;
148169
SCB->VTOR = backup->VTOR;
@@ -157,25 +178,77 @@ static void scb_resume(_scb_context_t *backup)
157178
SCB->MMFAR = backup->MMFAR;
158179
SCB->BFAR = backup->BFAR;
159180
SCB->AFSR = backup->AFSR;
181+
SCB->CPACR = backup->CPACR;
182+
}
183+
184+
#if defined(CONFIG_FPU)
185+
static void fpu_power_down(void)
186+
{
187+
SCB->CPACR &= (~(CPACR_CP10_Msk | CPACR_CP11_Msk));
188+
SCnSCB->CPPWR |= (SCnSCB_CPPWR_SU11_Msk | SCnSCB_CPPWR_SU10_Msk);
189+
__DSB();
190+
__ISB();
191+
}
192+
193+
static void fpu_power_up(void)
194+
{
195+
SCnSCB->CPPWR &= (~(SCnSCB_CPPWR_SU11_Msk | SCnSCB_CPPWR_SU10_Msk));
196+
SCB->CPACR |= (CPACR_CP10_Msk | CPACR_CP11_Msk);
197+
__DSB();
198+
__ISB();
199+
}
200+
201+
#if !defined(CONFIG_FPU_SHARING)
202+
static void fpu_save(_fpu_context_t *backup)
203+
{
204+
backup->FPCCR = FPU->FPCCR;
205+
backup->FPCAR = FPU->FPCAR;
206+
backup->FPDSCR = FPU->FPDSCR;
207+
208+
__asm__ volatile("vstmia %0, {s0-s31}\n" : : "r"(backup->S) : "memory");
209+
}
210+
211+
static void fpu_restore(_fpu_context_t *backup)
212+
{
213+
FPU->FPCCR = backup->FPCCR;
214+
FPU->FPCAR = backup->FPCAR;
215+
FPU->FPDSCR = backup->FPDSCR;
216+
217+
__asm__ volatile("vldmia %0, {s0-s31}\n" : : "r"(backup->S) : "memory");
160218
}
219+
#endif /* !defined(CONFIG_FPU_SHARING) */
220+
#endif /* defined(CONFIG_FPU) */
161221

162222
int soc_s2ram_suspend(pm_s2ram_system_off_fn_t system_off)
163223
{
164224
int ret;
165225

166-
scb_suspend(&backup_data.scb_context);
167-
nvic_suspend(&backup_data.nvic_context);
168-
mpu_suspend(&backup_data.mpu_context);
226+
scb_save(&backup_data.scb_context);
227+
#if defined(CONFIG_FPU)
228+
#if !defined(CONFIG_FPU_SHARING)
229+
fpu_save(&backup_data.fpu_context);
230+
#endif
231+
fpu_power_down();
232+
#endif
233+
nvic_save(&backup_data.nvic_context);
234+
mpu_save(&backup_data.mpu_context);
169235
ret = arch_pm_s2ram_suspend(system_off);
170-
/* Cache is powered down so power up is needed even if s2ram failed. */
236+
/* Cache and FPU are powered down so power up is needed even if s2ram failed. */
171237
nrf_power_up_cache();
238+
#if defined(CONFIG_FPU)
239+
fpu_power_up();
240+
#if !defined(CONFIG_FPU_SHARING)
241+
/* Also the FPU content might be lost. */
242+
fpu_restore(&backup_data.fpu_context);
243+
#endif
244+
#endif
172245
if (ret < 0) {
173246
return ret;
174247
}
175248

176-
mpu_resume(&backup_data.mpu_context);
177-
nvic_resume(&backup_data.nvic_context);
178-
scb_resume(&backup_data.scb_context);
249+
mpu_restore(&backup_data.mpu_context);
250+
nvic_restore(&backup_data.nvic_context);
251+
scb_restore(&backup_data.scb_context);
179252

180253
return ret;
181254
}

0 commit comments

Comments
 (0)