1 /*
2 * Copyright (c) 2024 Ambiq Micro Inc. <www.ambiq.com>
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/kernel.h>
8 #include <zephyr/drivers/flash.h>
9 #include <zephyr/device.h>
10 #include <zephyr/devicetree.h>
11 #include <stdio.h>
12 #include <string.h>
13
14 #define SPI_FLASH_TEST_REGION_OFFSET 0xff000
15
16 #define SPI_FLASH_SECTOR_SIZE 4096
17
18 #define SPI_FLASH_MULTI_SECTOR_TEST
19
single_sector_test(const struct device * flash_dev)20 int single_sector_test(const struct device *flash_dev)
21 {
22 #if CONFIG_DCACHE
23 const uint8_t expected[]__aligned(CONFIG_DCACHE_LINE_SIZE) = {
24 #else
25 const uint8_t expected[] = {
26 #endif
27 0x55, 0xaa, 0x66, 0x99};
28 const size_t len = sizeof(expected);
29 #if CONFIG_DCACHE
30 uint8_t buf[sizeof(expected)]__aligned(CONFIG_DCACHE_LINE_SIZE);
31 #else
32 uint8_t buf[sizeof(expected)];
33 #endif
34
35 int rc;
36
37 printf("\nPerform test on single sector");
38 /* Write protection needs to be disabled before each write or
39 * erase, since the flash component turns on write protection
40 * automatically after completion of write and erase
41 * operations.
42 */
43 printf("\nTest 1: Flash erase\n");
44
45 /* Full flash erase if SPI_FLASH_TEST_REGION_OFFSET = 0 and
46 * SPI_FLASH_SECTOR_SIZE = flash size
47 */
48 rc = flash_erase(flash_dev, SPI_FLASH_TEST_REGION_OFFSET,
49 SPI_FLASH_SECTOR_SIZE);
50 if (rc != 0) {
51 printf("Flash erase failed! %d\n", rc);
52 } else {
53 printf("Flash erase succeeded!\n");
54 }
55
56 printf("\nTest 2: Flash write\n");
57
58 printf("Attempting to write %zu bytes\n", len);
59 rc = flash_write(flash_dev, SPI_FLASH_TEST_REGION_OFFSET, expected, len);
60 if (rc != 0) {
61 printf("Flash write failed! %d\n", rc);
62 return 1;
63 }
64
65 memset(buf, 0, len);
66 rc = flash_read(flash_dev, SPI_FLASH_TEST_REGION_OFFSET, buf, len);
67 if (rc != 0) {
68 printf("Flash read failed! %d\n", rc);
69 return 1;
70 }
71
72 if (memcmp(expected, buf, len) == 0) {
73 printf("Data read matches data written. Good!!\n");
74 } else {
75 const uint8_t *wp = expected;
76 const uint8_t *rp = buf;
77 const uint8_t *rpe = rp + len;
78
79 printf("Data read does not match data written!!\n");
80 while (rp < rpe) {
81 printf("%08x wrote %02x read %02x %s\n",
82 (uint32_t)(SPI_FLASH_TEST_REGION_OFFSET + (rp - buf)),
83 *wp, *rp, (*rp == *wp) ? "match" : "MISMATCH");
84 ++rp;
85 ++wp;
86 }
87 }
88 return rc;
89 }
90
91 #if defined SPI_FLASH_MULTI_SECTOR_TEST
92 int multi_sector_test(const struct device *flash_dev)
93 {
94 #if CONFIG_DCACHE
95 const uint8_t expected[]__aligned(CONFIG_DCACHE_LINE_SIZE) = {
96 #else
97 const uint8_t expected[] = {
98 #endif
99 0x55, 0xaa, 0x66, 0x99};
100 const size_t len = sizeof(expected);
101 #if CONFIG_DCACHE
102 uint8_t buf[sizeof(expected)]__aligned(CONFIG_DCACHE_LINE_SIZE);
103 #else
104 uint8_t buf[sizeof(expected)];
105 #endif
106 int rc;
107
108 printf("\nPerform test on multiple consequtive sectors");
109
110 /* Write protection needs to be disabled before each write or
111 * erase, since the flash component turns on write protection
112 * automatically after completion of write and erase
113 * operations.
114 */
115 printf("\nTest 1: Flash erase\n");
116
117 /* Full flash erase if SPI_FLASH_TEST_REGION_OFFSET = 0 and
118 * SPI_FLASH_SECTOR_SIZE = flash size
119 * Erase 2 sectors for check for erase of consequtive sectors
120 */
121 rc = flash_erase(flash_dev, SPI_FLASH_TEST_REGION_OFFSET, SPI_FLASH_SECTOR_SIZE * 2);
122 if (rc != 0) {
123 printf("Flash erase failed! %d\n", rc);
124 } else {
125 /* Read the content and check for erased */
126 memset(buf, 0, len);
127 size_t offs = SPI_FLASH_TEST_REGION_OFFSET;
128
129 while (offs < SPI_FLASH_TEST_REGION_OFFSET + 2 * SPI_FLASH_SECTOR_SIZE) {
130 rc = flash_read(flash_dev, offs, buf, len);
131 if (rc != 0) {
132 printf("Flash read failed! %d\n", rc);
133 return 1;
134 }
135 if (buf[0] != 0xff) {
136 printf("Flash erase failed at offset 0x%x got 0x%x\n",
137 offs, buf[0]);
138 return 1;
139 }
140 offs += SPI_FLASH_SECTOR_SIZE;
141 }
142 printf("Flash erase succeeded!\n");
143 }
144
145 printf("\nTest 2: Flash write\n");
146
147 size_t offs = SPI_FLASH_TEST_REGION_OFFSET;
148
149 while (offs < SPI_FLASH_TEST_REGION_OFFSET + 2 * SPI_FLASH_SECTOR_SIZE) {
150 printf("Attempting to write %zu bytes at offset 0x%x\n", len, offs);
151 rc = flash_write(flash_dev, offs, expected, len);
152 if (rc != 0) {
153 printf("Flash write failed! %d\n", rc);
154 return 1;
155 }
156
157 memset(buf, 0, len);
158 rc = flash_read(flash_dev, offs, buf, len);
159 if (rc != 0) {
160 printf("Flash read failed! %d\n", rc);
161 return 1;
162 }
163
164 if (memcmp(expected, buf, len) == 0) {
165 printf("Data read matches data written. Good!!\n");
166 } else {
167 const uint8_t *wp = expected;
168 const uint8_t *rp = buf;
169 const uint8_t *rpe = rp + len;
170
171 printf("Data read does not match data written!!\n");
172 while (rp < rpe) {
173 printf("%08x wrote %02x read %02x %s\n",
174 (uint32_t)(offs + (rp - buf)),
175 *wp, *rp, (*rp == *wp) ? "match" : "MISMATCH");
176 ++rp;
177 ++wp;
178 }
179 }
180 offs += SPI_FLASH_SECTOR_SIZE;
181 }
182 return rc;
183 }
184 #endif
185
186 int main(void)
187 {
188 const struct device *flash_dev = DEVICE_DT_GET(DT_ALIAS(flash0));
189
190 if (!device_is_ready(flash_dev)) {
191 printk("%s: device not ready.\n", flash_dev->name);
192 return 1;
193 }
194
195 printf("\n%s SPI flash testing\n", flash_dev->name);
196 printf("==========================\n");
197
198 if (single_sector_test(flash_dev)) {
199 return 1;
200 }
201 #if defined SPI_FLASH_MULTI_SECTOR_TEST
202 if (multi_sector_test(flash_dev)) {
203 return 1;
204 }
205 #endif
206 printf("==========================\n");
207 return 0;
208 }
209