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