Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 | /* * Copyright (c) 2024 Nordic Semiconductor ASA * SPDX-License-Identifier: Apache-2.0 */ #include <zephyr/kernel.h> #include <zephyr/sys/poweroff.h> #include <zephyr/toolchain.h> #include <zephyr/pm/policy.h> #include <zephyr/arch/common/pm_s2ram.h> #include <hal/nrf_resetinfo.h> #include <hal/nrf_lrcconf.h> #include <hal/nrf_memconf.h> #include <zephyr/cache.h> #include <power.h> #include "pm_s2ram.h" static void suspend_common(void) { /* Flush, disable and power down DCACHE */ sys_cache_data_flush_all(); sys_cache_data_disable(); nrf_memconf_ramblock_control_enable_set(NRF_MEMCONF, RAMBLOCK_POWER_ID, RAMBLOCK_CONTROL_BIT_DCACHE, false); if (IS_ENABLED(CONFIG_ICACHE)) { /* Disable and power down ICACHE */ sys_cache_instr_disable(); nrf_memconf_ramblock_control_enable_set(NRF_MEMCONF, RAMBLOCK_POWER_ID, RAMBLOCK_CONTROL_BIT_ICACHE, false); } /* Disable retention */ nrf_lrcconf_retain_set(NRF_LRCCONF010, NRF_LRCCONF_POWER_DOMAIN_0, false); nrf_lrcconf_poweron_force_set(NRF_LRCCONF010, NRF_LRCCONF_POWER_DOMAIN_0, false); } void nrf_poweroff(void) { nrf_resetinfo_resetreas_local_set(NRF_RESETINFO, 0); nrf_resetinfo_restore_valid_set(NRF_RESETINFO, false); nrf_lrcconf_retain_set(NRF_LRCCONF010, NRF_LRCCONF_POWER_MAIN, false); /* TODO: Move it around k_cpu_idle() implementation. */ nrf_lrcconf_poweron_force_set(NRF_LRCCONF010, NRF_LRCCONF_POWER_MAIN, false); nrf_lrcconf_poweron_force_set(NRF_LRCCONF010, NRF_LRCCONF_POWER_DOMAIN_0, false); suspend_common(); nrf_lrcconf_task_trigger(NRF_LRCCONF010, NRF_LRCCONF_TASK_SYSTEMOFFREADY); __set_BASEPRI(0); __ISB(); __DSB(); __WFI(); CODE_UNREACHABLE; } #if IS_ENABLED(CONFIG_PM_S2RAM) /* Resume domain after local suspend to RAM. */ static void sys_resume(void) { if (IS_ENABLED(CONFIG_ICACHE)) { /* Power up and re-enable ICACHE */ nrf_memconf_ramblock_control_enable_set(NRF_MEMCONF, RAMBLOCK_POWER_ID, RAMBLOCK_CONTROL_BIT_ICACHE, true); sys_cache_instr_enable(); } if (IS_ENABLED(CONFIG_DCACHE)) { /* Power up and re-enable DCACHE */ nrf_memconf_ramblock_control_enable_set(NRF_MEMCONF, RAMBLOCK_POWER_ID, RAMBLOCK_CONTROL_BIT_DCACHE, true); sys_cache_data_enable(); } /* Re-enable domain retention. */ nrf_lrcconf_retain_set(NRF_LRCCONF010, NRF_LRCCONF_POWER_DOMAIN_0, true); /* TODO: Move it around k_cpu_idle() implementation. */ nrf_lrcconf_poweron_force_set(NRF_LRCCONF010, NRF_LRCCONF_POWER_MAIN, !IS_ENABLED(CONFIG_SOC_NRF54H20_CPURAD)); } /* Function called during local domain suspend to RAM. */ static int sys_suspend_to_ram(void) { /* Set intormation which is used on domain wakeup to determine if resume from RAM shall * be performed. */ nrf_resetinfo_resetreas_local_set(NRF_RESETINFO, NRF_RESETINFO_RESETREAS_LOCAL_UNRETAINED_MASK); nrf_resetinfo_restore_valid_set(NRF_RESETINFO, true); nrf_lrcconf_poweron_force_set(NRF_LRCCONF010, NRF_LRCCONF_POWER_DOMAIN_0, false); nrf_lrcconf_poweron_force_set(NRF_LRCCONF010, NRF_LRCCONF_POWER_MAIN, false); suspend_common(); __set_BASEPRI(0); __ISB(); __DSB(); __WFI(); /* * We might reach this point is k_cpu_idle returns (there is a pre sleep hook that * can abort sleeping. */ return -EBUSY; } static void do_suspend_to_ram(void) { /* * Save the CPU context (including the return address),set the SRAM * marker and power off the system. */ if (soc_s2ram_suspend(sys_suspend_to_ram)) { return; } /* * On resuming or error we return exactly *HERE* */ sys_resume(); } #endif /* IS_ENABLED(CONFIG_PM_S2RAM) */ void pm_state_set(enum pm_state state, uint8_t substate_id) { if (state != PM_STATE_SUSPEND_TO_RAM) { k_cpu_idle(); return; } #if IS_ENABLED(CONFIG_PM_S2RAM) do_suspend_to_ram(); #endif } void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) { irq_unlock(0); } |