Skip to content

Commit

Permalink
[nrf fromlist] samples: nordic: system_off: use retained_mem on all t…
Browse files Browse the repository at this point in the history
…argets

Using bare-metal approach for retention configuration
is no longer compatible with sys_poweroff() implementation.

Upstream PR #: 82262

Signed-off-by: Nikodem Kastelik <[email protected]>
  • Loading branch information
nika-nordic committed Dec 3, 2024
1 parent 13aa9ab commit 017f77a
Show file tree
Hide file tree
Showing 11 changed files with 72 additions and 181 deletions.
2 changes: 1 addition & 1 deletion samples/boards/nordic/system_off/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@ find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(nrf_system_off)

target_sources(app PRIVATE src/main.c)
if (CONFIG_APP_USE_NRF_RETENTION OR CONFIG_APP_USE_RETAINED_MEM)
if (CONFIG_APP_USE_RETAINED_MEM)
target_sources(app PRIVATE src/retained.c)
endif()
16 changes: 1 addition & 15 deletions samples/boards/nordic/system_off/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,9 @@

mainmenu "Nordic SYSTEM_OFF demo"

choice
prompt "Use retention"
optional

config APP_USE_NRF_RETENTION
bool "Use state retention in system off using nRF POWER"
depends on SOC_COMPATIBLE_NRF52X && CRC
help
On some Nordic chips this application supports retaining
memory while in system off using POWER peripheral.
Select this to enable the feature.

config APP_USE_RETAINED_MEM
bool "Use state retention in system off using retained_mem driver"
depends on RETAINED_MEM

endchoice
select RETAINED_MEM

config GRTC_WAKEUP_ENABLE
bool "Use GRTC to wake up device from system off"
Expand Down
8 changes: 4 additions & 4 deletions samples/boards/nordic/system_off/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ deep sleep on Nordic platforms.
RAM Retention
=============

This sample can also can demonstrate RAM retention. By selecting
``CONFIG_APP_USE_NRF_RETENTION=y`` or ``CONFIG_APP_USE_RETAINED_MEM=y``
state related to number of boots, number of times system off was entered,
and total uptime since initial power-on are retained in a checksummed data structure.
This sample can also demonstrate RAM retention.
By selecting ``CONFIG_APP_USE_RETAINED_MEM=y`` state related to number of boots,
number of times system off was entered, and total uptime since initial power-on
are retained in a checksummed data structure.
RAM is configured to keep the containing section powered while in system-off mode.

Requirements
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/ {
sram0@2003f000 {
compatible = "zephyr,memory-region", "mmio-sram";
reg = <0x2003f000 DT_SIZE_K(4)>;
zephyr,memory-region = "RetainedMem";
status = "okay";

retainedmem0: retainedmem {
compatible = "zephyr,retained-ram";
status = "okay";
};
};

aliases {
retainedmemdevice = &retainedmem0;
};
};

&sram0 {
/* Shrink SRAM size to avoid overlap with retained memory region */
reg = <0x20000000 DT_SIZE_K(252)>;
};
22 changes: 22 additions & 0 deletions samples/boards/nordic/system_off/boards/nrf52dk_nrf52832.overlay
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/ {
sram0@20007000 {
compatible = "zephyr,memory-region", "mmio-sram";
reg = <0x20007000 DT_SIZE_K(4)>;
zephyr,memory-region = "RetainedMem";
status = "okay";

retainedmem0: retainedmem {
compatible = "zephyr,retained-ram";
status = "okay";
};
};

aliases {
retainedmemdevice = &retainedmem0;
};
};

&sram0 {
/* Shrink SRAM size to avoid overlap with retained memory region */
reg = <0x20000000 DT_SIZE_K(28)>;
};
27 changes: 7 additions & 20 deletions samples/boards/nordic/system_off/sample.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,32 +22,17 @@ tests:
- "system off demo"
- "Retained data not supported"
- "Entering system off; press sw0 to restart"
sample.boards.nrf.system_off.nrf_retained:
sample.boards.nrf.system_off.retained_mem:
integration_platforms:
- nrf52840dk/nrf52840
platform_allow:
- nrf52840dk/nrf52840
- nrf52dk/nrf52832
extra_configs:
- CONFIG_APP_USE_NRF_RETENTION=y
harness: console
harness_config:
type: multi_line
ordered: true
regex:
- "system off demo"
- "Retained data: INVALID"
- "Boot count: 1"
- "Off count: 0"
- "Active Ticks:"
- "Entering system off; press sw0 to restart"
sample.boards.nrf.system_off.retained_mem:
extra_args: DTC_OVERLAY_FILE="boards/nrf54l15dk_nrf54l15_cpuapp_retained_mem.overlay"
platform_allow:
- nrf54l15dk/nrf54l15/cpuapp
- nrf54l15dk/nrf54l10/cpuapp
- nrf54l15dk/nrf54l05/cpuapp
extra_configs:
- CONFIG_APP_USE_RETAINED_MEM=y
- CONFIG_RETAINED_MEM=y
harness: console
harness_config:
type: multi_line
Expand All @@ -62,6 +47,8 @@ tests:
sample.boards.nrf.system_off.grtc_wakeup:
platform_allow:
- nrf54l15dk/nrf54l15/cpuapp
- nrf54l15dk/nrf54l10/cpuapp
- nrf54l15dk/nrf54l05/cpuapp
extra_configs:
- CONFIG_GRTC_WAKEUP_ENABLE=y
harness: console
Expand All @@ -79,13 +66,13 @@ tests:
- "Retained data not supported"
- "Entering system off; wait 2 seconds to restart"
sample.boards.nrf.system_off.retained_mem.grtc_wakeup:
extra_args: DTC_OVERLAY_FILE="boards/nrf54l15dk_nrf54l15_cpuapp_retained_mem.overlay"
platform_allow:
- nrf54l15dk/nrf54l15/cpuapp
- nrf54l15dk/nrf54l10/cpuapp
- nrf54l15dk/nrf54l05/cpuapp
extra_configs:
- CONFIG_APP_USE_RETAINED_MEM=y
- CONFIG_GRTC_WAKEUP_ENABLE=y
- CONFIG_RETAINED_MEM=y
harness: console
harness_config:
type: multi_line
Expand Down
4 changes: 2 additions & 2 deletions samples/boards/nordic/system_off/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ int main(void)

printf("\n%s system off demo\n", CONFIG_BOARD);

if (IS_ENABLED(CONFIG_APP_USE_NRF_RETENTION) || IS_ENABLED(CONFIG_APP_USE_RETAINED_MEM)) {
if (IS_ENABLED(CONFIG_APP_USE_RETAINED_MEM)) {
bool retained_ok = retained_validate();

/* Increment for this boot attempt and update. */
Expand Down Expand Up @@ -81,7 +81,7 @@ int main(void)
return 0;
}

if (IS_ENABLED(CONFIG_APP_USE_NRF_RETENTION) || IS_ENABLED(CONFIG_APP_USE_RETAINED_MEM)) {
if (IS_ENABLED(CONFIG_APP_USE_RETAINED_MEM)) {
/* Update the retained state */
retained.off_count += 1;
retained_update();
Expand Down
152 changes: 13 additions & 139 deletions samples/boards/nordic/system_off/src/retained.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,147 +15,24 @@
#include <zephyr/sys/byteorder.h>
#include <zephyr/sys/crc.h>

#if CONFIG_APP_USE_NRF_RETENTION
#include <hal/nrf_power.h>

/* nRF52 RAM (really, RAM AHB slaves) are partitioned as:
* * Up to 8 blocks of two 4 KiBy byte "small" sections
* * A 9th block of with 32 KiBy "large" sections
*
* At time of writing the maximum number of large sections is 6, all
* within the first large block. Theoretically there could be more
* sections in the 9th block, and possibly more blocks.
*/

/* Inclusive address of RAM start */
#define SRAM_BEGIN (uintptr_t)DT_REG_ADDR(DT_NODELABEL(sram0))

/* Exclusive address of RAM end */
#define SRAM_END (SRAM_BEGIN + (uintptr_t)DT_REG_SIZE(DT_NODELABEL(sram0)))

/* Size of a controllable RAM section in the small blocks */
#define SMALL_SECTION_SIZE 4096

/* Number of controllable RAM sections in each of the lower blocks */
#define SMALL_SECTIONS_PER_BLOCK 2

/* Span of a small block */
#define SMALL_BLOCK_SIZE (SMALL_SECTIONS_PER_BLOCK * SMALL_SECTION_SIZE)

/* Number of small blocks */
#define SMALL_BLOCK_COUNT 8

/* Span of the SRAM area covered by small sections */
#define SMALL_SECTION_SPAN (SMALL_BLOCK_COUNT * SMALL_BLOCK_SIZE)

/* Inclusive address of the RAM range covered by large sections */
#define LARGE_SECTION_BEGIN (SRAM_BEGIN + SMALL_SECTION_SPAN)

/* Size of a controllable RAM section in large blocks */
#define LARGE_SECTION_SIZE 32768

#elif CONFIG_APP_USE_RETAINED_MEM
#if DT_NODE_HAS_STATUS_OKAY(DT_ALIAS(retainedmemdevice))
const static struct device *retained_mem_device = DEVICE_DT_GET(DT_ALIAS(retainedmemdevice));
#endif

/* Set or clear RAM retention in SYSTEM_OFF for the provided object.
*
* @param ptr pointer to the start of the retainable object
*
* @param len length of the retainable object
*
* @param enable true to enable retention, false to clear retention
*/
static int ram_range_retain(const void *ptr,
size_t len,
bool enable)
{
int rc = 0;

#if CONFIG_APP_USE_NRF_RETENTION
/* This only works for nRF52 with the POWER module.
* The other Nordic chips use a different low-level API,
* which is not currently used by this variant.
*/
uintptr_t addr = (uintptr_t)ptr;
uintptr_t addr_end = addr + len;

/* Error if the provided range is empty or doesn't lie
* entirely within the SRAM address space.
*/
if ((len == 0U)
|| (addr < SRAM_BEGIN)
|| (addr > (SRAM_END - len))) {
return -EINVAL;
}

/* Iterate over each section covered by the range, setting the
* corresponding RAM OFF retention bit in the parent block.
*/
do {
uintptr_t block_base = SRAM_BEGIN;
uint32_t section_size = SMALL_SECTION_SIZE;
uint32_t sections_per_block = SMALL_SECTIONS_PER_BLOCK;
bool is_large = (addr >= LARGE_SECTION_BEGIN);
uint8_t block = 0;

if (is_large) {
block = 8;
block_base = LARGE_SECTION_BEGIN;
section_size = LARGE_SECTION_SIZE;

/* RAM[x] supports only 16 sections, each its own bit
* for POWER (0..15) and RETENTION (16..31). We don't
* know directly how many sections are present, so
* assume they all are; the true limit will be
* determined by the SRAM size.
*/
sections_per_block = 16;
}

uint32_t section = (addr - block_base) / section_size;

if (section >= sections_per_block) {
block += section / sections_per_block;
section %= sections_per_block;
}

uint32_t section_mask =
(POWER_RAM_POWERSET_S0RETENTION_On
<< (section + POWER_RAM_POWERSET_S0RETENTION_Pos));

if (enable) {
nrf_power_rampower_mask_on(NRF_POWER, block, section_mask);
} else {
nrf_power_rampower_mask_off(NRF_POWER, block, section_mask);
}

/* Move to the first address in the next section. */
addr += section_size - (addr % section_size);
} while (addr < addr_end);
#elif CONFIG_APP_USE_RETAINED_MEM
/* Retention setting cannot be controlled runtime with retained_mem API */
(void)enable;
rc = retained_mem_write(retained_mem_device, 0, ptr, len);
#else
#error "Unsupported retention setting"
#error "retained_mem region not defined"
#endif

return rc;
}

/* Retained data must be defined in a no-init section to prevent the C
* runtime initialization from zeroing it before anybody can see it.
* It is not necesarry when retained_mem driver is utilized
* as in this case retained data is stored in an area not initialized in runtime.
*/
__noinit struct retained_data retained;
struct retained_data retained;

#define RETAINED_CRC_OFFSET offsetof(struct retained_data, crc)
#define RETAINED_CHECKED_SIZE (RETAINED_CRC_OFFSET + sizeof(retained.crc))

bool retained_validate(void)
{
int rc;

rc = retained_mem_read(retained_mem_device, 0, (uint8_t *)&retained, sizeof(retained));
__ASSERT_NO_MSG(rc == 0);

/* The residue of a CRC is what you get from the CRC over the
* message catenated with its CRC. This is the post-final-xor
* residue for CRC-32 (CRC-32/ISO-HDLC) which Zephyr calls
Expand All @@ -174,19 +51,13 @@ bool retained_validate(void)
/* Reset to accrue runtime from this session. */
retained.uptime_latest = 0;

/* Reconfigure to retain the state during system off, regardless of
* whether validation succeeded. Although these values can sometimes
* be observed to be preserved across System OFF, the product
* specification states they are not retained in that situation, and
* that can also be observed.
*/
(void)ram_range_retain(&retained, RETAINED_CHECKED_SIZE, true);

return valid;
}

void retained_update(void)
{
int rc;

uint64_t now = k_uptime_ticks();

retained.uptime_sum += (now - retained.uptime_latest);
Expand All @@ -196,4 +67,7 @@ void retained_update(void)
RETAINED_CRC_OFFSET);

retained.crc = sys_cpu_to_le32(crc);

rc = retained_mem_write(retained_mem_device, 0, (uint8_t *)&retained, sizeof(retained));
__ASSERT_NO_MSG(rc == 0);
}

0 comments on commit 017f77a

Please sign in to comment.