1 /*
2  * Copyright (c) 2017 Nordic Semiconductor ASA
3  * Copyright (c) 2015 Runtime Inc
4  * Copyright (c) 2020 Gerson Fernando Budke <nandojve@gmail.com>
5  * Copyright 2024 NXP
6  *
7  * SPDX-License-Identifier: Apache-2.0
8  */
9 
10 #include <zephyr/ztest.h>
11 #include <zephyr/drivers/flash.h>
12 #include <zephyr/storage/flash_map.h>
13 
14 #define SLOT1_PARTITION		slot1_partition
15 #define SLOT1_PARTITION_ID	FIXED_PARTITION_ID(SLOT1_PARTITION)
16 #define SLOT1_PARTITION_DEV	FIXED_PARTITION_DEVICE(SLOT1_PARTITION)
17 #define SLOT1_PARTITION_NODE	DT_NODELABEL(SLOT1_PARTITION)
18 #define SLOT1_PARTITION_OFFSET	FIXED_PARTITION_OFFSET(SLOT1_PARTITION)
19 
20 extern int flash_map_entries;
21 struct flash_sector fs_sectors[1024];
22 
ZTEST(flash_map,test_flash_area_disabled_device)23 ZTEST(flash_map, test_flash_area_disabled_device)
24 {
25 	const struct flash_area *fa;
26 	int rc;
27 
28 	/* Test that attempting to open a disabled flash area fails */
29 	rc = flash_area_open(FIXED_PARTITION_ID(disabled_a), &fa);
30 	zassert_equal(rc, -ENOENT, "Open did not fail");
31 	rc = flash_area_open(FIXED_PARTITION_ID(disabled_b), &fa);
32 	zassert_equal(rc, -ENOENT, "Open did not fail");
33 
34 	/* Note lack of tests for FIXED_PARTITION(...) instantiation,
35 	 * because this macro will fail, at compile time, if node does not
36 	 * exist or is disabled.
37 	 */
38 }
39 
ZTEST(flash_map,test_flash_area_device_is_ready)40 ZTEST(flash_map, test_flash_area_device_is_ready)
41 {
42 	const struct flash_area no_dev = {
43 		.fa_dev = NULL,
44 	};
45 
46 	zassert_false(flash_area_device_is_ready(NULL));
47 	zassert_false(flash_area_device_is_ready(&no_dev));
48 	/* The below just assumes that tests are executed so late that
49 	 * all devices are already initialized and ready.
50 	 */
51 	zassert_true(flash_area_device_is_ready(
52 			FIXED_PARTITION(SLOT1_PARTITION)));
53 }
54 
layout_match(const struct device * flash_dev,uint32_t sec_cnt)55 static void layout_match(const struct device *flash_dev, uint32_t sec_cnt)
56 {
57 	off_t off = 0;
58 	int i;
59 
60 	/* For each reported sector, check if it corresponds to real page on device */
61 	for (i = 0; i < sec_cnt; ++i) {
62 		struct flash_pages_info fpi;
63 
64 		zassert_ok(
65 			flash_get_page_info_by_offs(flash_dev, SLOT1_PARTITION_OFFSET + off, &fpi));
66 		/* Offset of page taken directly from device corresponds to offset
67 		 * within flash area
68 		 */
69 		zassert_equal(fpi.start_offset, fs_sectors[i].fs_off + SLOT1_PARTITION_OFFSET);
70 		zassert_equal(fpi.size, fs_sectors[i].fs_size);
71 		off += fs_sectors[i].fs_size;
72 	}
73 }
74 
75 /**
76  * @brief Test flash_area_get_sectors()
77  */
ZTEST(flash_map,test_flash_area_get_sectors)78 ZTEST(flash_map, test_flash_area_get_sectors)
79 {
80 	const struct flash_area *fa;
81 	const struct device *flash_dev_a = SLOT1_PARTITION_DEV;
82 	uint32_t sec_cnt;
83 	int rc;
84 
85 	fa = FIXED_PARTITION(SLOT1_PARTITION);
86 
87 	zassert_true(flash_area_device_is_ready(fa));
88 
89 	zassert_true(device_is_ready(flash_dev_a));
90 
91 	/* Device obtained by label should match the one from fa object */
92 	zassert_equal(fa->fa_dev, flash_dev_a, "Device for slot1_partition do not match");
93 
94 	memset(&fs_sectors[0], 0, sizeof(fs_sectors));
95 
96 	sec_cnt = ARRAY_SIZE(fs_sectors);
97 	rc = flash_area_get_sectors(SLOT1_PARTITION_ID, &sec_cnt, fs_sectors);
98 	zassert_true(rc == 0, "flash_area_get_sectors failed");
99 
100 	layout_match(flash_dev_a, sec_cnt);
101 }
102 
ZTEST(flash_map,test_flash_area_sectors)103 ZTEST(flash_map, test_flash_area_sectors)
104 {
105 	const struct flash_area *fa;
106 	uint32_t sec_cnt;
107 	int rc;
108 	const struct device *flash_dev_a = SLOT1_PARTITION_DEV;
109 
110 	fa = FIXED_PARTITION(SLOT1_PARTITION);
111 
112 	zassert_true(flash_area_device_is_ready(fa));
113 
114 	zassert_true(device_is_ready(flash_dev_a));
115 
116 	/* Device obtained by label should match the one from fa object */
117 	zassert_equal(fa->fa_dev, flash_dev_a, "Device for slot1_partition do not match");
118 
119 	sec_cnt = ARRAY_SIZE(fs_sectors);
120 	rc = flash_area_sectors(fa, &sec_cnt, fs_sectors);
121 	zassert_true(rc == 0, "flash_area_get_sectors failed");
122 
123 	layout_match(flash_dev_a, sec_cnt);
124 }
125 
ZTEST(flash_map,test_flash_area_erased_val)126 ZTEST(flash_map, test_flash_area_erased_val)
127 {
128 	const struct flash_parameters *param;
129 	const struct flash_area *fa;
130 	uint8_t val;
131 
132 	fa = FIXED_PARTITION(SLOT1_PARTITION);
133 
134 	val = flash_area_erased_val(fa);
135 
136 	param = flash_get_parameters(fa->fa_dev);
137 
138 	zassert_equal(param->erase_value, val,
139 		      "value different than the flash erase value");
140 }
141 
ZTEST(flash_map,test_fixed_partition_node_macros)142 ZTEST(flash_map, test_fixed_partition_node_macros)
143 {
144 	/* Test against changes in API */
145 	zassert_equal(FIXED_PARTITION_NODE_OFFSET(SLOT1_PARTITION_NODE),
146 		DT_REG_ADDR(SLOT1_PARTITION_NODE));
147 	zassert_equal(FIXED_PARTITION_NODE_SIZE(SLOT1_PARTITION_NODE),
148 		DT_REG_SIZE(SLOT1_PARTITION_NODE));
149 	zassert_equal(FIXED_PARTITION_NODE_DEVICE(SLOT1_PARTITION_NODE),
150 		DEVICE_DT_GET(DT_MTD_FROM_FIXED_PARTITION(SLOT1_PARTITION_NODE)));
151 
152 	/* Taking by node and taking by label should give same device */
153 	zassert_equal(FIXED_PARTITION_BY_NODE(DT_NODELABEL(SLOT1_PARTITION)),
154 		      FIXED_PARTITION(SLOT1_PARTITION));
155 }
156 
ZTEST(flash_map,test_flash_area_erase_and_flatten)157 ZTEST(flash_map, test_flash_area_erase_and_flatten)
158 {
159 	int i;
160 	bool erased = true;
161 	int rc;
162 	const struct flash_area *fa;
163 	const struct device *flash_dev;
164 
165 	fa = FIXED_PARTITION(SLOT1_PARTITION);
166 
167 	/* First erase the area so it's ready for use. */
168 	flash_dev = flash_area_get_device(fa);
169 
170 	rc = flash_erase(flash_dev, fa->fa_off, fa->fa_size);
171 	zassert_true(rc == 0, "flash area erase fail");
172 
173 	rc = flash_fill(flash_dev, 0xaa, fa->fa_off, fa->fa_size);
174 	zassert_true(rc == 0, "flash device fill fail");
175 
176 	rc = flash_area_erase(fa, 0, fa->fa_size);
177 	zassert_true(rc == 0, "flash area erase fail");
178 
179 	TC_PRINT("Flash area info:\n");
180 	TC_PRINT("\tpointer:\t %p\n", &fa);
181 	TC_PRINT("\toffset:\t %ld\n", (long)fa->fa_off);
182 	TC_PRINT("\tsize:\t %ld\n", (long)fa->fa_size);
183 
184 	/* we work under assumption that flash_fill is working and tested */
185 	i = 0;
186 	while (erased && i < fa->fa_size) {
187 		uint8_t buf[32];
188 		int chunk = MIN(sizeof(buf), fa->fa_size - i);
189 
190 		rc = flash_read(flash_dev, fa->fa_off + i, buf, chunk);
191 		zassert_equal(rc, 0, "Unexpected read fail with error %d", rc);
192 		for (int ii = 0; ii < chunk; ++ii, ++i) {
193 			if ((uint8_t)buf[ii] != (uint8_t)flash_area_erased_val(fa)) {
194 				erased = false;
195 				break;
196 			}
197 		}
198 	}
199 	zassert_true(erased, "Erase failed at dev abosolute offset index %d",
200 		     i + fa->fa_off);
201 
202 	rc = flash_fill(flash_dev, 0xaa, fa->fa_off, fa->fa_size);
203 	zassert_true(rc == 0, "flash device fill fail");
204 
205 	rc = flash_area_flatten(fa, 0, fa->fa_size);
206 
207 	erased = true;
208 	i = 0;
209 	while (erased && i < fa->fa_size) {
210 		uint8_t buf[32];
211 		int chunk = MIN(sizeof(buf), fa->fa_size - i);
212 
213 		rc = flash_read(flash_dev, fa->fa_off + i, buf, chunk);
214 		zassert_equal(rc, 0, "Unexpected read fail with error %d", rc);
215 		for (int ii = 0; ii < chunk; ++ii, ++i) {
216 			if ((uint8_t)buf[ii] != (uint8_t)flash_area_erased_val(fa)) {
217 				erased = false;
218 				break;
219 			}
220 		}
221 	}
222 	zassert_true(erased, "Flatten/Erase failed at dev absolute offset %d",
223 		     i + fa->fa_off);
224 }
225 
226 ZTEST_SUITE(flash_map, NULL, NULL, NULL, NULL, NULL);
227