blob: 336d2304bada08b7f106b4cbb83603739727e2be [file] [log] [blame]
Sheetal Tigadoli6c4db5d2020-01-06 00:08:24 +05301/*
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 */
36const 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
43static 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
54static 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 */
79static inline int spi_flash_cmd_write_enable(struct spi_flash *flash)
80{
81 return spi_flash_cmd(CMD_WRITE_ENABLE, NULL, 0);
82}
83
84static 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
114static 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
141static 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
155int 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
190int 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
234int 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
276int 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
305probe_fail:
306 spi_release_bus();
307 return ret;
308}