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