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