1.. _retention_api:
2
3Retention System
4################
5
6The retention system provides an API which allows applications to read and
7write data from and to memory areas or devices that retain the data while the
8device is powered. This allows for sharing information between different
9applications or within a single application without losing state information
10when a device reboots. The stored data should not persist in the event of a
11power failure (or during some low-power modes on some devices) nor should it be
12stored to a non-volatile storage like :ref:`flash_api`, :ref:`eeprom_api`, or
13battery-backed RAM.
14
15The retention system builds on top of the retained data driver, and adds
16additional software-level features to it for ensuring the validity of data.
17Optionally, a magic header can be used to check if the front of
18the retained data memory section contains this specific value, and an optional
19checksum (1, 2, or 4-bytes in size) of the stored data can be appended to the
20end of the data. Additionally, the retention system API allows partitioning of
21the retained data sections into multiple distinct areas. For example, a 64-byte
22retained data area could be split up into 4 bytes for a boot mode, 16 bytes for
23a timestamp, 44 bytes for a last log message. All of these sections can be
24accessed or updated independently. The prefix and checksum can be set
25per-instance using devicetree.
26
27Devicetree setup
28****************
29
30To use the retention system, a retained data driver must be setup for the board
31you are using, there is a zephyr driver which can be used which will use some
32RAM as non-init for this purpose. The retention system is then initialised as a
33child node of this device 1 or more times - note that the memory region will
34need to be decremented to account for this reserved portion of RAM. See the
35following example (examples in this guide are based on the
36:ref:`nrf52840dk_nrf52840` board and memory layout):
37
38.. code-block:: devicetree
39
40	/ {
41		sram@2003FC00 {
42			compatible = "zephyr,memory-region", "mmio-sram";
43			reg = <0x2003FC00 DT_SIZE_K(1)>;
44			zephyr,memory-region = "RetainedMem";
45			status = "okay";
46
47			retainedmem {
48				compatible = "zephyr,retained-ram";
49				status = "okay";
50				#address-cells = <1>;
51				#size-cells = <1>;
52
53				/* This creates a 256-byte partition */
54				retention0: retention@0 {
55					compatible = "zephyr,retention";
56					status = "okay";
57
58					/* The total size of this area is 256
59					 * bytes which includes the prefix and
60					 * checksum, this means that the usable
61					 * data storage area is 256 - 3 = 253
62					 * bytes
63					 */
64					reg = <0x0 0x100>;
65
66					/* This is the prefix which must appear
67					 * at the front of the data
68					 */
69					prefix = [08 04];
70
71					/* This uses a 1-byte checksum */
72					checksum = <1>;
73				};
74
75				/* This creates a 768-byte partition */
76				retention1: retention@100 {
77					compatible = "zephyr,retention";
78					status = "okay";
79
80					/* Start position must be after the end
81					 * of the previous partition. The total
82					 * size of this area is 768 bytes which
83					 * includes the prefix and checksum,
84					 * this means that the usable data
85					 * storage area is 768 - 6 = 762 bytes
86					 */
87					reg = <0x100 0x300>;
88
89					/* This is the prefix which must appear
90					 * at the front of the data
91					 */
92					prefix = [00 11 55 88 fa bc];
93
94					/* If omitted, there will be no
95					 * checksum
96					 */
97				};
98			};
99		};
100	};
101
102	/* Reduce SRAM0 usage by 1KB to account for non-init area */
103	&sram0 {
104		reg = <0x20000000 DT_SIZE_K(255)>;
105	};
106
107The retention areas can then be accessed using the data retention API (once
108enabled with :kconfig:option:`CONFIG_RETENTION`, which requires that
109:kconfig:option:`CONFIG_RETAINED_MEM` be enabled) by getting the device by
110using:
111
112.. code-block:: C
113
114	#include <zephyr/device.h>
115	#include <zephyr/retention/retention.h>
116
117	const struct device *retention1 = DEVICE_DT_GET(DT_NODELABEL(retention1));
118	const struct device *retention2 = DEVICE_DT_GET(DT_NODELABEL(retention2));
119
120When the write function is called, the magic header and checksum (if enabled)
121will be set on the area, and it will be marked as valid from that point
122onwards.
123
124Mutex protection
125****************
126
127Mutex protection of retention areas is enabled by default when applications are
128compiled with multithreading support. This means that different threads can
129safely call the retention functions without clashing with other concurrent
130thread function usage, but means that retention functions cannot be used from
131ISRs. It is possible to disable mutex protection globally on all retention
132areas by enabling :kconfig:option:`CONFIG_RETENTION_MUTEX_FORCE_DISABLE` -
133users are then responsible for ensuring that the function calls do not conflict
134with each other. Note that to use this, retention driver mutex support must
135also be disabled by enabling
136:kconfig:option:`CONFIG_RETAINED_MEM_MUTEX_FORCE_DISABLE`.
137
138.. _boot_mode_api:
139
140Boot mode
141*********
142
143An addition to the retention subsystem is a boot mode interface, this can be
144used to dynamically change the state of an application or run a different
145application with a minimal set of functions when a device is rebooted (an
146example is to have a buttonless way of entering mcuboot's serial recovery
147feature from the main application).
148
149To use the boot mode feature, a data retention entry must exist in the device
150tree, which is dedicated for use as the boot mode selection (the user area data
151size only needs to be a single byte), and this area be assigned to the chosen
152node of ``zephyr,boot-mode``. See the following example:
153
154.. code-block:: devicetree
155
156	/ {
157		sram@2003FFFF {
158			compatible = "zephyr,memory-region", "mmio-sram";
159			reg = <0x2003FFFF 0x1>;
160			zephyr,memory-region = "RetainedMem";
161			status = "okay";
162
163			retainedmem {
164				compatible = "zephyr,retained-ram";
165				status = "okay";
166				#address-cells = <1>;
167				#size-cells = <1>;
168
169				retention0: retention@0 {
170					compatible = "zephyr,retention";
171					status = "okay";
172					reg = <0x0 0x1>;
173				};
174			};
175		};
176
177		chosen {
178			zephyr,boot-mode = &retention0;
179		};
180	};
181
182	/* Reduce SRAM0 usage by 1 byte to account for non-init area */
183	&sram0 {
184		reg = <0x20000000 0x3FFFF>;
185	};
186
187The boot mode interface can be enabled with
188:kconfig:option:`CONFIG_RETENTION_BOOT_MODE` and then accessed by using the
189boot mode functions. If using mcuboot with serial recovery, it can be built
190with ``CONFIG_MCUBOOT_SERIAL`` and ``CONFIG_BOOT_SERIAL_BOOT_MODE`` enabled
191which will allow rebooting directly into the serial recovery mode by using:
192
193.. code-block:: C
194
195	#include <zephyr/retention/bootmode.h>
196	#include <zephyr/sys/reboot.h>
197
198	bootmode_set(BOOT_MODE_TYPE_BOOTLOADER);
199	sys_reboot(0);
200
201Retention system modules
202************************
203
204Modules can expand the functionality of the retention system by using it as a
205transport (e.g. between a bootloader and application).
206
207.. toctree::
208    :maxdepth: 1
209
210    blinfo.rst
211
212API Reference
213*************
214
215Retention system API
216====================
217
218.. doxygengroup:: retention_api
219
220Boot mode interface
221===================
222
223.. doxygengroup:: boot_mode_interface
224