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