1 /*
2  * Copyright (c) 2016 Linaro Limited
3  *               2016 Intel Corporation.
4  * Copyright (c) 2024 Nordic Semiconductor ASA
5  *
6  * SPDX-License-Identifier: Apache-2.0
7  */
8 
9 #include <zephyr/kernel.h>
10 #include <zephyr/drivers/flash.h>
11 #include <zephyr/storage/flash_map.h>
12 #include <zephyr/device.h>
13 #include <zephyr/devicetree.h>
14 #include <stdio.h>
15 
16 
17 #define TEST_PARTITION	storage_partition
18 
19 #define TEST_PARTITION_OFFSET	FIXED_PARTITION_OFFSET(TEST_PARTITION)
20 #define TEST_PARTITION_DEVICE	FIXED_PARTITION_DEVICE(TEST_PARTITION)
21 
22 #define FLASH_PAGE_SIZE   4096
23 #define TEST_DATA_WORD_0  0x1122
24 #define TEST_DATA_WORD_1  0xaabb
25 #define TEST_DATA_WORD_2  0xabcd
26 #define TEST_DATA_WORD_3  0x1234
27 
28 #define FLASH_TEST_OFFSET2 0x41234
29 #define FLASH_TEST_PAGE_IDX 37
30 
31 #if defined(CONFIG_FLASH_HAS_EXPLICIT_ERASE) &&	\
32 	defined(CONFIG_FLASH_HAS_NO_EXPLICIT_ERASE)
33 #define FLASH_PE_RUNTIME_CHECK(cond) (cond)
34 #elif defined(CONFIG_FLASH_HAS_EXPLICIT_ERASE)
35 #define FLASH_PE_RUNTIME_CHECK(cond) (true)
36 #else
37 /* Assumed IS_ENABLED(CONFIG_FLASH_HAS_NO_EXPLICIT_ERASE) */
38 #define FLASH_PE_RUNTIME_CHECK(cond) (false)
39 #endif
40 
41 /**
42  * Depending on value of condition erase a device or not. The condition
43  * is supposed to be value of erase_requirement picked up from
44  * flash_parameters.flags for device.
45  */
erase_when_needed(const struct device * dev,bool condition,uint32_t off,uint32_t size)46 static void erase_when_needed(const struct device *dev, bool condition,
47 			     uint32_t off, uint32_t size)
48 {
49 	/*
50 	 * Alwayes invoke erase when there are only erase requiring devices,
51 	 * never invoke erase when there are no devices requiring erase,
52 	 * always check condition if there are both kind of devices.
53 	 */
54 	if (FLASH_PE_RUNTIME_CHECK(condition)) {
55 		if (flash_erase(dev, off, size) != 0) {
56 			printf("   Erase failed!\n");
57 		} else {
58 			printf("   Erase succeeded!\n");
59 		}
60 	} else {
61 		(void)condition;
62 		printf("   Erase not required by device\n");
63 	}
64 }
65 
main(void)66 int main(void)
67 {
68 	const struct device *flash_dev = TEST_PARTITION_DEVICE;
69 	struct flash_parameters flash_params;
70 	uint32_t buf_array_1[4] = { TEST_DATA_WORD_0, TEST_DATA_WORD_1,
71 				    TEST_DATA_WORD_2, TEST_DATA_WORD_3 };
72 	uint32_t buf_array_2[4] = { TEST_DATA_WORD_3, TEST_DATA_WORD_1,
73 				    TEST_DATA_WORD_2, TEST_DATA_WORD_0 };
74 	uint32_t buf_array_3[8] = { TEST_DATA_WORD_0, TEST_DATA_WORD_1,
75 				    TEST_DATA_WORD_2, TEST_DATA_WORD_3,
76 				    TEST_DATA_WORD_0, TEST_DATA_WORD_1,
77 				    TEST_DATA_WORD_2, TEST_DATA_WORD_3 };
78 	uint32_t buf_word = 0U;
79 	uint32_t i, offset;
80 
81 	memcpy(&flash_params, flash_get_parameters(flash_dev), sizeof(flash_params));
82 
83 	printf("\nNordic nRF5 Internal Storage Sample\n");
84 	printf("=====================================\n");
85 
86 	if (!device_is_ready(flash_dev)) {
87 		printf("Internal storage device not ready\n");
88 		return 0;
89 	}
90 
91 	printf("\nTest 1: Internal storage erase page at 0x%x\n", TEST_PARTITION_OFFSET);
92 	erase_when_needed(flash_dev,
93 			  flash_params_get_erase_cap(&flash_params) & FLASH_ERASE_C_EXPLICIT,
94 			  TEST_PARTITION_OFFSET, FLASH_PAGE_SIZE);
95 
96 	printf("\nTest 2: Internal storage write (word array 1)\n");
97 	for (i = 0U; i < ARRAY_SIZE(buf_array_1); i++) {
98 		offset = TEST_PARTITION_OFFSET + (i << 2);
99 		printf("   Attempted to write %x at 0x%x\n", buf_array_1[i],
100 				offset);
101 		if (flash_write(flash_dev, offset, &buf_array_1[i],
102 					sizeof(uint32_t)) != 0) {
103 			printf("   Write failed!\n");
104 			return 0;
105 		}
106 		printf("   Attempted to read 0x%x\n", offset);
107 		if (flash_read(flash_dev, offset, &buf_word,
108 					sizeof(uint32_t)) != 0) {
109 			printf("   Read failed!\n");
110 			return 0;
111 		}
112 		printf("   Data read: %x\n", buf_word);
113 		if (buf_array_1[i] == buf_word) {
114 			printf("   Data read matches data written. Good!\n");
115 		} else {
116 			printf("   Data read does not match data written!\n");
117 		}
118 	}
119 
120 	offset = TEST_PARTITION_OFFSET;
121 	printf("\nTest 3: Internal storage erase (2 pages at 0x%x)\n", offset);
122 	erase_when_needed(flash_dev,
123 			  flash_params_get_erase_cap(&flash_params) & FLASH_ERASE_C_EXPLICIT,
124 			  offset, FLASH_PAGE_SIZE * 2);
125 	printf("\nTest 4: Internal storage write (word array 2)\n");
126 	for (i = 0U; i < ARRAY_SIZE(buf_array_2); i++) {
127 		offset = TEST_PARTITION_OFFSET + (i << 2);
128 		printf("   Attempted to write %x at 0x%x\n", buf_array_2[i],
129 				offset);
130 		if (flash_write(flash_dev, offset, &buf_array_2[i],
131 					sizeof(uint32_t)) != 0) {
132 			printf("   Write failed!\n");
133 			return 0;
134 		}
135 		printf("   Attempted to read 0x%x\n", offset);
136 		if (flash_read(flash_dev, offset, &buf_word,
137 					sizeof(uint32_t)) != 0) {
138 			printf("   Read failed!\n");
139 			return 0;
140 		}
141 		printf("   Data read: %x\n", buf_word);
142 		if (buf_array_2[i] == buf_word) {
143 			printf("   Data read matches data written. Good!\n");
144 		} else {
145 			printf("   Data read does not match data written!\n");
146 		}
147 	}
148 
149 	printf("\nTest 5: Internal storage erase page at 0x%x\n", TEST_PARTITION_OFFSET);
150 	erase_when_needed(flash_dev,
151 			  flash_params_get_erase_cap(&flash_params) & FLASH_ERASE_C_EXPLICIT,
152 			  TEST_PARTITION_OFFSET, FLASH_PAGE_SIZE);
153 
154 	printf("\nTest 6: Non-word aligned write (word array 3)\n");
155 	for (i = 0U; i < ARRAY_SIZE(buf_array_3); i++) {
156 		offset = TEST_PARTITION_OFFSET + (i << 2) + 1;
157 		printf("   Attempted to write %x at 0x%x\n", buf_array_3[i],
158 				offset);
159 		if (flash_write(flash_dev, offset, &buf_array_3[i],
160 					sizeof(uint32_t)) != 0) {
161 			printf("   Write failed!\n");
162 			return 0;
163 		}
164 		printf("   Attempted to read 0x%x\n", offset);
165 		if (flash_read(flash_dev, offset, &buf_word,
166 					sizeof(uint32_t)) != 0) {
167 			printf("   Read failed!\n");
168 			return 0;
169 		}
170 		printf("   Data read: %x\n", buf_word);
171 		if (buf_array_3[i] == buf_word) {
172 			printf("   Data read matches data written. Good!\n");
173 		} else {
174 			printf("   Data read does not match data written!\n");
175 		}
176 	}
177 
178 #if defined(CONFIG_FLASH_PAGE_LAYOUT)
179 	struct flash_pages_info info;
180 	int rc;
181 
182 	rc = flash_get_page_info_by_offs(flash_dev, FLASH_TEST_OFFSET2, &info);
183 
184 	printf("\nTest 7: Page layout API\n");
185 
186 	if (!rc) {
187 		printf("   Offset  0x%08x:\n", FLASH_TEST_OFFSET2);
188 		printf("     belongs to the page %u of start offset 0x%08lx\n",
189 		       info.index, (unsigned long) info.start_offset);
190 		printf("     and the size of 0x%08x B.\n", info.size);
191 	} else {
192 		printf("   Error: flash_get_page_info_by_offs returns %d\n",
193 		       rc);
194 	}
195 
196 	rc = flash_get_page_info_by_idx(flash_dev, FLASH_TEST_PAGE_IDX, &info);
197 
198 	if (!rc) {
199 		printf("   Page of number %u has start offset 0x%08lx\n",
200 		       FLASH_TEST_PAGE_IDX,
201 		       (unsigned long) info.start_offset);
202 		printf("     and size of 0x%08x B.\n", info.size);
203 		if (info.index == FLASH_TEST_PAGE_IDX) {
204 			printf("     Page index resolved properly\n");
205 		} else {
206 			printf("     ERROR: Page index resolved to %u\n",
207 			       info.index);
208 		}
209 
210 	} else {
211 		printf("   Error: flash_get_page_info_by_idx returns %d\n", rc);
212 	}
213 
214 	printf("   SoC flash consists of %u pages.\n",
215 	       flash_get_page_count(flash_dev));
216 
217 #endif
218 
219 	printf("\nTest 8: Write block size API\n");
220 	printf("   write-block-size = %u\n", flash_params.write_block_size);
221 
222 	printf("\nFinished!\n");
223 	return 0;
224 }
225