1 /*
2 * Copyright (c) 2024 Nordic Semiconductor ASA
3 * SPDX-License-Identifier: Apache-2.0
4 */
5
6 #include <zephyr/kernel.h>
7 #include <zephyr/sys/poweroff.h>
8 #include <zephyr/toolchain.h>
9 #include <zephyr/pm/policy.h>
10 #include <zephyr/arch/common/pm_s2ram.h>
11 #include <hal/nrf_resetinfo.h>
12 #include <hal/nrf_memconf.h>
13 #include <zephyr/cache.h>
14 #include <power.h>
15 #include <soc_lrcconf.h>
16 #include "soc.h"
17 #include "pm_s2ram.h"
18
19 extern sys_snode_t soc_node;
20
common_suspend(void)21 static void common_suspend(void)
22 {
23 if (IS_ENABLED(CONFIG_DCACHE)) {
24 /* Flush, disable and power down DCACHE */
25 sys_cache_data_flush_all();
26 sys_cache_data_disable();
27 nrf_memconf_ramblock_control_enable_set(NRF_MEMCONF, RAMBLOCK_POWER_ID,
28 RAMBLOCK_CONTROL_BIT_DCACHE, false);
29 }
30
31 if (IS_ENABLED(CONFIG_ICACHE)) {
32 /* Disable and power down ICACHE */
33 sys_cache_instr_disable();
34 nrf_memconf_ramblock_control_enable_set(NRF_MEMCONF, RAMBLOCK_POWER_ID,
35 RAMBLOCK_CONTROL_BIT_ICACHE, false);
36 }
37
38 soc_lrcconf_poweron_release(&soc_node, NRF_LRCCONF_POWER_DOMAIN_0);
39 }
40
common_resume(void)41 static void common_resume(void)
42 {
43 if (IS_ENABLED(CONFIG_ICACHE)) {
44 /* Power up and re-enable ICACHE */
45 nrf_memconf_ramblock_control_enable_set(NRF_MEMCONF, RAMBLOCK_POWER_ID,
46 RAMBLOCK_CONTROL_BIT_ICACHE, true);
47 sys_cache_instr_enable();
48 }
49
50 if (IS_ENABLED(CONFIG_DCACHE)) {
51 /* Power up and re-enable DCACHE */
52 nrf_memconf_ramblock_control_enable_set(NRF_MEMCONF, RAMBLOCK_POWER_ID,
53 RAMBLOCK_CONTROL_BIT_DCACHE, true);
54 sys_cache_data_enable();
55 }
56
57 soc_lrcconf_poweron_request(&soc_node, NRF_LRCCONF_POWER_DOMAIN_0);
58 }
59
nrf_poweroff(void)60 void nrf_poweroff(void)
61 {
62 nrf_resetinfo_resetreas_local_set(NRF_RESETINFO, 0);
63 nrf_resetinfo_restore_valid_set(NRF_RESETINFO, false);
64
65 #if !defined(CONFIG_SOC_NRF54H20_CPURAD)
66 /* Disable retention */
67 nrf_lrcconf_retain_set(NRF_LRCCONF010, NRF_LRCCONF_POWER_MAIN, false);
68 nrf_lrcconf_retain_set(NRF_LRCCONF010, NRF_LRCCONF_POWER_DOMAIN_0, false);
69 #endif
70 common_suspend();
71
72 nrf_lrcconf_task_trigger(NRF_LRCCONF010, NRF_LRCCONF_TASK_SYSTEMOFFREADY);
73
74 __set_BASEPRI(0);
75 __ISB();
76 __DSB();
77 __WFI();
78
79 CODE_UNREACHABLE;
80 }
81
s2idle_enter(uint8_t substate_id)82 static void s2idle_enter(uint8_t substate_id)
83 {
84 switch (substate_id) {
85 case 0:
86 /* Substate for idle with cache powered on - not implemented yet. */
87 break;
88 case 1: /* Substate for idle with cache retained - not implemented yet. */
89 break;
90 case 2: /* Substate for idle with cache disabled. */
91 #if !defined(CONFIG_SOC_NRF54H20_CPURAD)
92 soc_lrcconf_poweron_request(&soc_node, NRF_LRCCONF_POWER_MAIN);
93 #endif
94 common_suspend();
95 break;
96 default: /* Unknown substate. */
97 return;
98 }
99
100 __set_BASEPRI(0);
101 __ISB();
102 __DSB();
103 __WFI();
104 }
105
s2idle_exit(uint8_t substate_id)106 static void s2idle_exit(uint8_t substate_id)
107 {
108 switch (substate_id) {
109 case 0:
110 /* Substate for idle with cache powered on - not implemented yet. */
111 break;
112 case 1: /* Substate for idle with cache retained - not implemented yet. */
113 break;
114 case 2: /* Substate for idle with cache disabled. */
115 common_resume();
116 #if !defined(CONFIG_SOC_NRF54H20_CPURAD)
117 soc_lrcconf_poweron_release(&soc_node, NRF_LRCCONF_POWER_MAIN);
118 #endif
119 default: /* Unknown substate. */
120 return;
121 }
122 }
123
124 #if defined(CONFIG_PM_S2RAM)
125 /* Resume domain after local suspend to RAM. */
s2ram_exit(void)126 static void s2ram_exit(void)
127 {
128 common_resume();
129 #if !defined(CONFIG_SOC_NRF54H20_CPURAD)
130 /* Re-enable domain retention. */
131 nrf_lrcconf_retain_set(NRF_LRCCONF010, NRF_LRCCONF_POWER_DOMAIN_0, true);
132 #endif
133 }
134
135 /* Function called during local domain suspend to RAM. */
sys_suspend_to_ram(void)136 static int sys_suspend_to_ram(void)
137 {
138 /* Set intormation which is used on domain wakeup to determine if resume from RAM shall
139 * be performed.
140 */
141 nrf_resetinfo_resetreas_local_set(NRF_RESETINFO,
142 NRF_RESETINFO_RESETREAS_LOCAL_UNRETAINED_MASK);
143 nrf_resetinfo_restore_valid_set(NRF_RESETINFO, true);
144
145 #if !defined(CONFIG_SOC_NRF54H20_CPURAD)
146 /* Disable retention */
147 nrf_lrcconf_retain_set(NRF_LRCCONF010, NRF_LRCCONF_POWER_DOMAIN_0, false);
148 #endif
149 common_suspend();
150
151 __set_BASEPRI(0);
152 __ISB();
153 __DSB();
154 __WFI();
155 /*
156 * We might reach this point is k_cpu_idle returns (there is a pre sleep hook that
157 * can abort sleeping.
158 */
159 return -EBUSY;
160 }
161
s2ram_enter(void)162 static void s2ram_enter(void)
163 {
164 /*
165 * Save the CPU context (including the return address),set the SRAM
166 * marker and power off the system.
167 */
168 if (soc_s2ram_suspend(sys_suspend_to_ram)) {
169 return;
170 }
171 }
172 #endif /* defined(CONFIG_PM_S2RAM) */
173
pm_state_set(enum pm_state state,uint8_t substate_id)174 void pm_state_set(enum pm_state state, uint8_t substate_id)
175 {
176 if (state == PM_STATE_SUSPEND_TO_IDLE) {
177 __disable_irq();
178 s2idle_enter(substate_id);
179 /* Resume here. */
180 s2idle_exit(substate_id);
181 __enable_irq();
182 }
183 #if defined(CONFIG_PM_S2RAM)
184 else if (state == PM_STATE_SUSPEND_TO_RAM) {
185 __disable_irq();
186 s2ram_enter();
187 /* On resuming or error we return exactly *HERE* */
188 s2ram_exit();
189 __enable_irq();
190 }
191 #endif
192 else {
193 k_cpu_idle();
194 }
195 }
196
pm_state_exit_post_ops(enum pm_state state,uint8_t substate_id)197 void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id)
198 {
199 irq_unlock(0);
200 }
201