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