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