• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2019-2020, Broadcom
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include <stdbool.h>
8 #include <stddef.h>
9 #include <stdint.h>
10 
11 #include <common/debug.h>
12 #include <drivers/delay_timer.h>
13 #include <errno.h>
14 
15 #include <sf.h>
16 #include <spi.h>
17 
18 #define SPI_FLASH_CMD_LEN	4
19 #define QSPI_WAIT_TIMEOUT_US	200000U /* usec */
20 
21 #define FINFO(jedec_id, ext_id, _sector_size, _n_sectors, _page_size, _flags) \
22 		.id = {							\
23 			((jedec_id) >> 16) & 0xff,			\
24 			((jedec_id) >> 8) & 0xff,			\
25 			(jedec_id) & 0xff,				\
26 			((ext_id) >> 8) & 0xff,				\
27 			(ext_id) & 0xff,				\
28 			},						\
29 		.id_len = (!(jedec_id) ? 0 : (3 + ((ext_id) ? 2 : 0))),	\
30 		.sector_size = (_sector_size),				\
31 		.n_sectors = (_n_sectors),				\
32 		.page_size = _page_size,				\
33 		.flags = (_flags),
34 
35 /* SPI/QSPI flash device params structure */
36 const struct spi_flash_info spi_flash_ids[] = {
37 	{"W25Q64CV", FINFO(0xef4017, 0x0, 64 * 1024, 128, 256, WR_QPP | SECT_4K)},
38 	{"W25Q64DW", FINFO(0xef6017, 0x0, 64 * 1024, 128, 256, WR_QPP | SECT_4K)},
39 	{"W25Q32",   FINFO(0xef4016, 0x0, 64 * 1024, 64,  256, SECT_4K)},
40 	{"MX25l3205D",  FINFO(0xc22016, 0x0, 64 * 1024, 64, 256, SECT_4K)},
41 };
42 
spi_flash_addr(uint32_t addr,uint8_t * cmd)43 static void spi_flash_addr(uint32_t addr, uint8_t *cmd)
44 {
45 	/*
46 	 * cmd[0] holds a SPI Flash command, stored earlier
47 	 * cmd[1/2/3] holds 24bit flash address
48 	 */
49 	cmd[1] = addr >> 16;
50 	cmd[2] = addr >> 8;
51 	cmd[3] = addr >> 0;
52 }
53 
spi_flash_read_id(void)54 static const struct spi_flash_info *spi_flash_read_id(void)
55 {
56 	const struct spi_flash_info *info;
57 	uint8_t id[SPI_FLASH_MAX_ID_LEN];
58 	int ret;
59 
60 	ret = spi_flash_cmd(CMD_READ_ID, id, SPI_FLASH_MAX_ID_LEN);
61 	if (ret < 0) {
62 		ERROR("SF: Error %d reading JEDEC ID\n", ret);
63 		return NULL;
64 	}
65 
66 	for (info = spi_flash_ids; info->name != NULL; info++) {
67 		if (info->id_len) {
68 			if (!memcmp(info->id, id, info->id_len))
69 				return info;
70 		}
71 	}
72 
73 	printf("SF: unrecognized JEDEC id bytes: %02x, %02x, %02x\n",
74 	       id[0], id[1], id[2]);
75 	return NULL;
76 }
77 
78 /* Enable writing on the SPI flash */
spi_flash_cmd_write_enable(struct spi_flash * flash)79 static inline int spi_flash_cmd_write_enable(struct spi_flash *flash)
80 {
81 	return spi_flash_cmd(CMD_WRITE_ENABLE, NULL, 0);
82 }
83 
spi_flash_cmd_wait(struct spi_flash * flash)84 static int spi_flash_cmd_wait(struct spi_flash *flash)
85 {
86 	uint8_t cmd;
87 	uint32_t i;
88 	uint8_t status;
89 	int ret;
90 
91 	i = 0;
92 	while (1) {
93 		cmd = CMD_RDSR;
94 		ret = spi_flash_cmd_read(&cmd, 1, &status, 1);
95 		if (ret < 0) {
96 			ERROR("SF: cmd wait failed\n");
97 			break;
98 		}
99 		if (!(status & STATUS_WIP))
100 			break;
101 
102 		i++;
103 		if (i >= QSPI_WAIT_TIMEOUT_US) {
104 			ERROR("SF: cmd wait timeout\n");
105 			ret = -1;
106 			break;
107 		}
108 		udelay(1);
109 	}
110 
111 	return ret;
112 }
113 
spi_flash_write_common(struct spi_flash * flash,const uint8_t * cmd,size_t cmd_len,const void * buf,size_t buf_len)114 static int spi_flash_write_common(struct spi_flash *flash, const uint8_t *cmd,
115 				  size_t cmd_len, const void *buf,
116 				  size_t buf_len)
117 {
118 	int ret;
119 
120 	ret = spi_flash_cmd_write_enable(flash);
121 	if (ret < 0) {
122 		ERROR("SF: enabling write failed\n");
123 		return ret;
124 	}
125 
126 	ret = spi_flash_cmd_write(cmd, cmd_len, buf, buf_len);
127 	if (ret < 0) {
128 		ERROR("SF: write cmd failed\n");
129 		return ret;
130 	}
131 
132 	ret = spi_flash_cmd_wait(flash);
133 	if (ret < 0) {
134 		ERROR("SF: write timed out\n");
135 		return ret;
136 	}
137 
138 	return ret;
139 }
140 
spi_flash_read_common(const uint8_t * cmd,size_t cmd_len,void * data,size_t data_len)141 static int spi_flash_read_common(const uint8_t *cmd, size_t cmd_len,
142 				 void *data, size_t data_len)
143 {
144 	int ret;
145 
146 	ret = spi_flash_cmd_read(cmd, cmd_len, data, data_len);
147 	if (ret < 0) {
148 		ERROR("SF: read cmd failed\n");
149 		return ret;
150 	}
151 
152 	return ret;
153 }
154 
spi_flash_read(struct spi_flash * flash,uint32_t offset,uint32_t len,void * data)155 int spi_flash_read(struct spi_flash *flash, uint32_t offset,
156 		   uint32_t len, void *data)
157 {
158 	uint32_t read_len = 0, read_addr;
159 	uint8_t cmd[SPI_FLASH_CMD_LEN];
160 	int ret;
161 
162 	ret = spi_claim_bus();
163 	if (ret) {
164 		ERROR("SF: unable to claim SPI bus\n");
165 		return ret;
166 	}
167 
168 	cmd[0] = CMD_READ_NORMAL;
169 	while (len) {
170 		read_addr = offset;
171 		read_len = MIN(flash->page_size, (len - read_len));
172 		spi_flash_addr(read_addr, cmd);
173 
174 		ret = spi_flash_read_common(cmd, sizeof(cmd), data, read_len);
175 		if (ret < 0) {
176 			ERROR("SF: read failed\n");
177 			break;
178 		}
179 
180 		offset += read_len;
181 		len -= read_len;
182 		data += read_len;
183 	}
184 	SPI_DEBUG("SF read done\n");
185 
186 	spi_release_bus();
187 	return ret;
188 }
189 
spi_flash_write(struct spi_flash * flash,uint32_t offset,uint32_t len,void * buf)190 int spi_flash_write(struct spi_flash *flash, uint32_t offset,
191 		    uint32_t len, void *buf)
192 {
193 	unsigned long byte_addr, page_size;
194 	uint8_t cmd[SPI_FLASH_CMD_LEN];
195 	uint32_t chunk_len, actual;
196 	uint32_t write_addr;
197 	int ret;
198 
199 	ret = spi_claim_bus();
200 	if (ret) {
201 		ERROR("SF: unable to claim SPI bus\n");
202 		return ret;
203 	}
204 
205 	page_size = flash->page_size;
206 
207 	cmd[0] = flash->write_cmd;
208 	for (actual = 0; actual < len; actual += chunk_len) {
209 		write_addr = offset;
210 		byte_addr = offset % page_size;
211 		chunk_len = MIN(len - actual,
212 				(uint32_t)(page_size - byte_addr));
213 		spi_flash_addr(write_addr, cmd);
214 
215 		SPI_DEBUG("SF:0x%p=>cmd:{0x%02x 0x%02x%02x%02x} chunk_len:%d\n",
216 			  buf + actual, cmd[0], cmd[1],
217 			  cmd[2], cmd[3], chunk_len);
218 
219 		ret = spi_flash_write_common(flash, cmd, sizeof(cmd),
220 					     buf + actual, chunk_len);
221 		if (ret < 0) {
222 			ERROR("SF: write cmd failed\n");
223 			break;
224 		}
225 
226 		offset += chunk_len;
227 	}
228 	SPI_DEBUG("SF write done\n");
229 
230 	spi_release_bus();
231 	return ret;
232 }
233 
spi_flash_erase(struct spi_flash * flash,uint32_t offset,uint32_t len)234 int spi_flash_erase(struct spi_flash *flash, uint32_t offset, uint32_t len)
235 {
236 	uint8_t cmd[SPI_FLASH_CMD_LEN];
237 	uint32_t erase_size, erase_addr;
238 	int ret;
239 
240 	erase_size = flash->erase_size;
241 
242 	if (offset % erase_size || len % erase_size) {
243 		ERROR("SF: Erase offset/length not multiple of erase size\n");
244 		return -1;
245 	}
246 
247 	ret = spi_claim_bus();
248 	if (ret) {
249 		ERROR("SF: unable to claim SPI bus\n");
250 		return ret;
251 	}
252 
253 	cmd[0] = flash->erase_cmd;
254 	while (len) {
255 		erase_addr = offset;
256 		spi_flash_addr(erase_addr, cmd);
257 
258 		SPI_DEBUG("SF: erase %2x %2x %2x %2x (%x)\n", cmd[0], cmd[1],
259 			cmd[2], cmd[3], erase_addr);
260 
261 		ret = spi_flash_write_common(flash, cmd, sizeof(cmd), NULL, 0);
262 		if (ret < 0) {
263 			ERROR("SF: erase failed\n");
264 			break;
265 		}
266 
267 		offset += erase_size;
268 		len -= erase_size;
269 	}
270 	SPI_DEBUG("sf erase done\n");
271 
272 	spi_release_bus();
273 	return ret;
274 }
275 
spi_flash_probe(struct spi_flash * flash)276 int spi_flash_probe(struct spi_flash *flash)
277 {
278 	const struct spi_flash_info *info = NULL;
279 	int ret;
280 
281 	ret = spi_claim_bus();
282 	if (ret) {
283 		ERROR("SF: Unable to claim SPI bus\n");
284 		ERROR("SF: probe failed\n");
285 		return ret;
286 	}
287 
288 	info = spi_flash_read_id();
289 	if (!info)
290 		goto probe_fail;
291 
292 	INFO("Flash Name: %s sectors %x, sec size %x\n",
293 	     info->name, info->n_sectors,
294 	     info->sector_size);
295 	flash->size = info->n_sectors * info->sector_size;
296 	flash->sector_size = info->sector_size;
297 	flash->page_size = info->page_size;
298 	flash->flags = info->flags;
299 
300 	flash->read_cmd = CMD_READ_NORMAL;
301 	flash->write_cmd = CMD_PAGE_PROGRAM;
302 	flash->erase_cmd = CMD_ERASE_64K;
303 	flash->erase_size = ERASE_SIZE_64K;
304 
305 probe_fail:
306 	spi_release_bus();
307 	return ret;
308 }
309