1 /*
2  * Copyright 2025 NXP
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/ztest.h>
8 #include <zephyr/drivers/flash.h>
9 #include <zephyr/devicetree.h>
10 
11 #ifdef CONFIG_BOOTLOADER_MCUBOOT
12 #define TEST_FLASH_PART_NODE DT_NODELABEL(boot_partition)
13 #else
14 #define TEST_FLASH_PART_NODE DT_NODELABEL(slot1_partition)
15 #endif
16 
17 #define TEST_FLASH_PART_OFFSET DT_REG_ADDR(TEST_FLASH_PART_NODE)
18 #define TEST_FLASH_PART_SIZE   DT_REG_SIZE(TEST_FLASH_PART_NODE)
19 
20 #define TEST_FLASH_CONTROLLER_NODE DT_MTD_FROM_FIXED_PARTITION(TEST_FLASH_PART_NODE)
21 
22 #define PATTERN_SIZE 256
23 
24 static const struct device *flash_controller = DEVICE_DT_GET(TEST_FLASH_CONTROLLER_NODE);
25 
26 static uint8_t pattern[PATTERN_SIZE];
27 
28 static const off_t test_area_offset = TEST_FLASH_PART_OFFSET;
29 static const size_t test_area_size = TEST_FLASH_PART_SIZE & ~(PATTERN_SIZE - 1);
30 static const off_t test_area_end = test_area_offset + test_area_size;
31 static const size_t number_of_slots = test_area_size / PATTERN_SIZE;
32 
verify_block(off_t pos,uint8_t * expected_data,size_t size)33 static int verify_block(off_t pos, uint8_t *expected_data, size_t size)
34 {
35 	uint8_t buffer[size];
36 
37 	if (flash_read(flash_controller, pos, buffer, size) != 0) {
38 		return -EIO;
39 	}
40 
41 	if (memcmp(expected_data, buffer, size) != 0) {
42 		return -EBADMSG;
43 	}
44 
45 	return 0;
46 }
47 
flash_setup(void)48 static void *flash_setup(void)
49 {
50 	bool pattern_available = true;
51 
52 	TC_PRINT("test_area_size = %zu MB\n", test_area_size >> 20);
53 
54 	/* Initialize pattern */
55 	for (int i = 0; i < sizeof(pattern); i++) {
56 		pattern[i] = i;
57 	}
58 
59 	for (off_t pos = test_area_offset; pos < test_area_end; pos += PATTERN_SIZE) {
60 		int res = verify_block(pos, pattern, sizeof(pattern));
61 
62 		if (res == -EBADMSG) {
63 			pattern_available = false;
64 			break;
65 		} else if (res < 0) {
66 			/* fail at any other errors */
67 			zassert_ok(res);
68 			return NULL;
69 		}
70 	}
71 
72 	if (!pattern_available) {
73 		TC_PRINT("Erasing test area\n");
74 		zassert_ok(flash_erase(flash_controller, TEST_FLASH_PART_OFFSET, test_area_size));
75 
76 		TC_PRINT("Writing pattern\n");
77 		for (off_t pos = test_area_offset; pos < test_area_end; pos += PATTERN_SIZE) {
78 			zassert_ok(flash_write(flash_controller, pos, pattern, sizeof(pattern)));
79 		}
80 	} else {
81 		TC_PRINT("Pattern is already available\n");
82 	}
83 
84 	return NULL;
85 }
86 
ZTEST(flash_interface,test_sequential_read_pattern)87 ZTEST(flash_interface, test_sequential_read_pattern)
88 {
89 	int amount = CONFIG_TEST_SEQUENTIAL_READ_PATTERN_AMOUNT;
90 	off_t slot = 0;
91 
92 	zassert_not_equal(number_of_slots, 0);
93 
94 	for (int i = 0; i < amount; i++) {
95 		if ((i & 255) == 0) {
96 			TC_PRINT("Verifying pattern sequentially (%i/%i)\n", i + 1, amount);
97 		}
98 		zassert_ok(verify_block(test_area_offset + (slot * PATTERN_SIZE), pattern,
99 					sizeof(pattern)));
100 		slot = (slot + 1) % number_of_slots;
101 	}
102 }
103 
ZTEST(flash_interface,test_sequential_alternating_read_pattern)104 ZTEST(flash_interface, test_sequential_alternating_read_pattern)
105 {
106 	int amount = CONFIG_TEST_SEQUENTIAL_ALTERNATING_READ_PATTERN_AMOUNT;
107 	off_t slot1 = 0;
108 	off_t slot2 = number_of_slots / 2;
109 
110 	zassert_not_equal(number_of_slots, 0);
111 
112 	for (int i = 0; i < amount; i++) {
113 		if ((i & 255) == 0) {
114 			TC_PRINT(
115 				"Verifying pattern sequentially on alternating positions (%i/%i)\n",
116 				i + 1, amount);
117 		}
118 		zassert_ok(verify_block(test_area_offset + (slot1 * PATTERN_SIZE), pattern,
119 					sizeof(pattern)));
120 		zassert_ok(verify_block(test_area_offset + (slot2 * PATTERN_SIZE), pattern,
121 					sizeof(pattern)));
122 		slot1 = (slot1 + 1) % number_of_slots;
123 		slot2 = (slot2 + 1) % number_of_slots;
124 	}
125 }
126 
127 ZTEST_SUITE(flash_interface, NULL, flash_setup, NULL, NULL, NULL);
128