1 /*
2 * Copyright (c) 2024 Ambiq Micro Inc. <www.ambiq.com>
3 * SPDX-License-Identifier: Apache-2.0
4 */
5
6 #include <zephyr/device.h>
7 #include <zephyr/drivers/mspi.h>
8 #include <zephyr/drivers/mspi_emul.h>
9 #include <zephyr/drivers/flash.h>
10 #include <zephyr/ztest.h>
11
12 #define MSPI_BUS_NODE DT_ALIAS(mspi0)
13
14 #define MSPI_FLASH_TEST_REGION_OFFSET 0x0
15
16 #define MSPI_FLASH_SECTOR_SIZE 4096
17
18 #define MSPI_FLASH_TEST_SIZE 3000
19
20 static const struct device *mspi_devices[] = {
21 DT_FOREACH_CHILD_STATUS_OKAY_SEP(MSPI_BUS_NODE, DEVICE_DT_GET, (,))
22 };
23
24 static uint8_t expected[MSPI_FLASH_TEST_SIZE];
25 static uint8_t actual[MSPI_FLASH_TEST_SIZE];
26
prepare_test_pattern(uint32_t pattern_index,uint8_t * actualf,uint32_t len)27 static void prepare_test_pattern(uint32_t pattern_index, uint8_t *actualf, uint32_t len)
28 {
29 uint32_t *pui32TxPtr = (uint32_t *)actualf;
30 uint8_t *pui8TxPtr = (uint8_t *)actualf;
31
32 switch (pattern_index) {
33 case 0:
34 /* 0x5555AAAA */
35 for (uint32_t i = 0; i < len / 4; i++) {
36 pui32TxPtr[i] = (0x5555AAAA);
37 }
38 break;
39 case 1:
40 /* 0xFFFF0000 */
41 for (uint32_t i = 0; i < len / 4; i++) {
42 pui32TxPtr[i] = (0xFFFF0000);
43 }
44 break;
45 case 2:
46 /* walking */
47 for (uint32_t i = 0; i < len; i++) {
48 pui8TxPtr[i] = 0x01 << (i % 8);
49 }
50 break;
51 case 3:
52 /* incremental from 1 */
53 for (uint32_t i = 0; i < len; i++) {
54 pui8TxPtr[i] = ((i + 1) & 0xFF);
55 }
56 break;
57 case 4:
58 /* decremental from 0xff */
59 for (uint32_t i = 0; i < len; i++) {
60 /* decrement starting from 0xff */
61 pui8TxPtr[i] = (0xff - i) & 0xFF;
62 }
63 break;
64 default:
65 /* incremental from 1 */
66 for (uint32_t i = 0; i < len; i++) {
67 pui8TxPtr[i] = ((i + 1) & 0xFF);
68 }
69 break;
70 }
71 }
72
test_multi_sector_rw(const struct device * flash_dev)73 static int test_multi_sector_rw(const struct device *flash_dev)
74 {
75 int rc = 0;
76 const struct flash_pages_layout *layout = NULL;
77 size_t layout_size = 0;
78 size_t min_page_size = -1;
79 size_t offs;
80
81 TC_PRINT("\n===================================================================\n");
82 TC_PRINT("Perform test on multiple consequtive sectors on %s\n", flash_dev->name);
83
84 TC_PRINT("\nTest 0: Get Flash page layout\n");
85
86 const struct flash_driver_api *api = flash_dev->api;
87
88 api->page_layout(flash_dev, &layout, &layout_size);
89
90 if (layout && layout_size) {
91 TC_PRINT("----pages-------size----\n");
92 for (int i = 0; i < layout_size; ++i) {
93 TC_PRINT("%2d: 0x%-8X 0x%-8x\n", i, layout[i].pages_count,
94 layout[i].pages_size);
95 min_page_size = MIN(min_page_size, layout[i].pages_size);
96 }
97 } else {
98 TC_PRINT("Empty flash_pages_layout!\n");
99 return TC_FAIL;
100 }
101
102 TC_PRINT("\nPage size selected: %d\n", min_page_size);
103
104 for (int i = 0; i < MSPI_FLASH_TEST_SIZE; i += min_page_size) {
105 prepare_test_pattern(i % 5, expected + i,
106 MIN(min_page_size, MSPI_FLASH_TEST_SIZE - i));
107 }
108
109 TC_PRINT("\nTest 1: Flash erase\n");
110
111 /* Full flash erase if MSPI_FLASH_TEST_REGION_OFFSET = 0 and
112 * MSPI_FLASH_SECTOR_SIZE = flash size
113 * Erase 2 sectors for check for erase of consequtive sectors
114 */
115 rc = flash_erase(flash_dev, MSPI_FLASH_TEST_REGION_OFFSET, MSPI_FLASH_SECTOR_SIZE * 2);
116 if (rc != 0) {
117 TC_PRINT("Flash erase failed! %d\n", rc);
118 return TC_FAIL;
119 }
120 /* Read the content and check for erased */
121 memset(actual, 0, MSPI_FLASH_TEST_SIZE);
122
123 offs = MSPI_FLASH_TEST_REGION_OFFSET;
124 while (offs < MSPI_FLASH_TEST_REGION_OFFSET + 2 * MSPI_FLASH_SECTOR_SIZE) {
125 rc = flash_read(flash_dev, offs, actual, MSPI_FLASH_TEST_SIZE);
126 if (rc != 0) {
127 TC_PRINT("Flash read failed! %d\n", rc);
128 return TC_FAIL;
129 }
130 if (actual[0] != 0xff) {
131 TC_PRINT("Flash erase failed at offset 0x%x got 0x%x\n", offs,
132 actual[0]);
133 return TC_FAIL;
134 }
135 offs += MSPI_FLASH_SECTOR_SIZE;
136 }
137 TC_PRINT("Flash erase succeeded!\n");
138
139 TC_PRINT("\nTest 2: Flash write\n");
140
141 offs = MSPI_FLASH_TEST_REGION_OFFSET;
142 while (offs < MSPI_FLASH_TEST_REGION_OFFSET + 2 * MSPI_FLASH_SECTOR_SIZE) {
143 TC_PRINT("\nAttempting to write %zu bytes at offset 0x%x\n", MSPI_FLASH_TEST_SIZE,
144 offs);
145 rc = flash_write(flash_dev, offs, expected, MSPI_FLASH_TEST_SIZE);
146 if (rc != 0) {
147 TC_PRINT("Flash write failed! %d\n", rc);
148 return TC_FAIL;
149 }
150
151 memset(actual, 0, MSPI_FLASH_TEST_SIZE);
152 rc = flash_read(flash_dev, offs, actual, MSPI_FLASH_TEST_SIZE);
153 if (rc != 0) {
154 TC_PRINT("Flash read failed! %d\n", rc);
155 return TC_FAIL;
156 }
157
158 if (memcmp(expected, actual, MSPI_FLASH_TEST_SIZE) == 0) {
159 TC_PRINT("Data read matches data written. Good!!\n");
160 } else {
161 const uint8_t *wp = expected;
162 const uint8_t *rp = actual;
163 const uint8_t *rpe = rp + MSPI_FLASH_TEST_SIZE;
164 int count = 0;
165
166 TC_PRINT("Data read does not match data written!!\n");
167 while (rp < rpe) {
168 if (*rp != *wp) {
169 TC_PRINT("%08x wrote %02x read %02x MISMATCH\n",
170 (uint32_t)(offs + (rp - actual)), *wp, *rp);
171 count++;
172 }
173 if (count > 100) {
174 TC_PRINT("Too many data mismatch!!\n");
175 break;
176 }
177 ++rp;
178 ++wp;
179 }
180 return TC_FAIL;
181 }
182 offs += MSPI_FLASH_SECTOR_SIZE;
183 }
184
185 return TC_PASS;
186 }
187
ZTEST(mspi_flash,test_multi_sector_rw)188 ZTEST(mspi_flash, test_multi_sector_rw)
189 {
190
191 for (int idx = 0; idx < ARRAY_SIZE(mspi_devices); ++idx) {
192
193 zassert_true(device_is_ready(mspi_devices[idx]),
194 "flash%d is not ready", idx);
195 zassert_true(test_multi_sector_rw(mspi_devices[idx]) == TC_PASS);
196
197 }
198
199 }
200
201 ZTEST_SUITE(mspi_flash, NULL, NULL, NULL, NULL, NULL);
202