]>
Commit | Line | Data |
---|---|---|
4d5e29a6 | 1 | /* |
cba65a77 | 2 | * SPI Flash Core |
4d5e29a6 | 3 | * |
cba65a77 | 4 | * Copyright (C) 2015 Jagan Teki <jteki@openedev.com> |
4d5e29a6 | 5 | * Copyright (C) 2013 Jagannadha Sutradharudu Teki, Xilinx Inc. |
cba65a77 JT |
6 | * Copyright (C) 2010 Reinhard Meyer, EMK Elektronik |
7 | * Copyright (C) 2008 Atmel Corporation | |
4d5e29a6 | 8 | * |
0c88a84a | 9 | * SPDX-License-Identifier: GPL-2.0+ |
4d5e29a6 JT |
10 | */ |
11 | ||
12 | #include <common.h> | |
c6136aad | 13 | #include <errno.h> |
ff063ed4 | 14 | #include <malloc.h> |
3847c0c1 | 15 | #include <mapmem.h> |
4d5e29a6 JT |
16 | #include <spi.h> |
17 | #include <spi_flash.h> | |
41b358d7 | 18 | #include <linux/log2.h> |
7bd1c59b | 19 | #include <dma.h> |
4d5e29a6 | 20 | |
898e76c9 | 21 | #include "sf_internal.h" |
4d5e29a6 | 22 | |
3847c0c1 JT |
23 | DECLARE_GLOBAL_DATA_PTR; |
24 | ||
4d5e29a6 JT |
25 | static void spi_flash_addr(u32 addr, u8 *cmd) |
26 | { | |
27 | /* cmd[0] is actual command */ | |
28 | cmd[1] = addr >> 16; | |
29 | cmd[2] = addr >> 8; | |
30 | cmd[3] = addr >> 0; | |
31 | } | |
32 | ||
cb375185 | 33 | static int read_sr(struct spi_flash *flash, u8 *rs) |
4d5e29a6 | 34 | { |
4d5e29a6 | 35 | int ret; |
9f4322fd | 36 | u8 cmd; |
4d5e29a6 | 37 | |
9f4322fd JT |
38 | cmd = CMD_READ_STATUS; |
39 | ret = spi_flash_read_common(flash, &cmd, 1, rs, 1); | |
4d5e29a6 | 40 | if (ret < 0) { |
9f4322fd | 41 | debug("SF: fail to read status register\n"); |
4d5e29a6 JT |
42 | return ret; |
43 | } | |
44 | ||
45 | return 0; | |
46 | } | |
47 | ||
baaaa753 JT |
48 | static int read_fsr(struct spi_flash *flash, u8 *fsr) |
49 | { | |
50 | int ret; | |
51 | const u8 cmd = CMD_FLAG_STATUS; | |
52 | ||
53 | ret = spi_flash_read_common(flash, &cmd, 1, fsr, 1); | |
54 | if (ret < 0) { | |
55 | debug("SF: fail to read flag status register\n"); | |
56 | return ret; | |
57 | } | |
58 | ||
59 | return 0; | |
60 | } | |
61 | ||
cb375185 | 62 | static int write_sr(struct spi_flash *flash, u8 ws) |
06795122 | 63 | { |
06795122 JT |
64 | u8 cmd; |
65 | int ret; | |
66 | ||
9f4322fd | 67 | cmd = CMD_WRITE_STATUS; |
2ba863fa | 68 | ret = spi_flash_write_common(flash, &cmd, 1, &ws, 1); |
06795122 | 69 | if (ret < 0) { |
9f4322fd | 70 | debug("SF: fail to write status register\n"); |
06795122 JT |
71 | return ret; |
72 | } | |
73 | ||
9f4322fd | 74 | return 0; |
06795122 | 75 | } |
06795122 | 76 | |
d08a1baf | 77 | #if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND) |
cb375185 | 78 | static int read_cr(struct spi_flash *flash, u8 *rc) |
6cba6fdf | 79 | { |
6cba6fdf | 80 | int ret; |
9f4322fd | 81 | u8 cmd; |
6cba6fdf | 82 | |
9f4322fd JT |
83 | cmd = CMD_READ_CONFIG; |
84 | ret = spi_flash_read_common(flash, &cmd, 1, rc, 1); | |
6cba6fdf | 85 | if (ret < 0) { |
9f4322fd | 86 | debug("SF: fail to read config register\n"); |
6cba6fdf JT |
87 | return ret; |
88 | } | |
89 | ||
90 | return 0; | |
91 | } | |
92 | ||
cb375185 | 93 | static int write_cr(struct spi_flash *flash, u8 wc) |
d08a1baf | 94 | { |
9f4322fd | 95 | u8 data[2]; |
d08a1baf JT |
96 | u8 cmd; |
97 | int ret; | |
98 | ||
cb375185 | 99 | ret = read_sr(flash, &data[0]); |
9f4322fd | 100 | if (ret < 0) |
d08a1baf | 101 | return ret; |
d08a1baf | 102 | |
9f4322fd JT |
103 | cmd = CMD_WRITE_STATUS; |
104 | data[1] = wc; | |
105 | ret = spi_flash_write_common(flash, &cmd, 1, &data, 2); | |
106 | if (ret) { | |
107 | debug("SF: fail to write config register\n"); | |
108 | return ret; | |
d08a1baf JT |
109 | } |
110 | ||
9f4322fd | 111 | return 0; |
d08a1baf JT |
112 | } |
113 | #endif | |
114 | ||
c56ae751 JT |
115 | #ifdef CONFIG_SPI_FLASH_STMICRO |
116 | static int read_evcr(struct spi_flash *flash, u8 *evcr) | |
117 | { | |
118 | int ret; | |
119 | const u8 cmd = CMD_READ_EVCR; | |
120 | ||
121 | ret = spi_flash_read_common(flash, &cmd, 1, evcr, 1); | |
122 | if (ret < 0) { | |
123 | debug("SF: error reading EVCR\n"); | |
124 | return ret; | |
125 | } | |
126 | ||
127 | return 0; | |
128 | } | |
129 | ||
130 | static int write_evcr(struct spi_flash *flash, u8 evcr) | |
131 | { | |
132 | u8 cmd; | |
133 | int ret; | |
134 | ||
135 | cmd = CMD_WRITE_EVCR; | |
136 | ret = spi_flash_write_common(flash, &cmd, 1, &evcr, 1); | |
137 | if (ret < 0) { | |
138 | debug("SF: error while writing EVCR register\n"); | |
139 | return ret; | |
140 | } | |
141 | ||
142 | return 0; | |
143 | } | |
144 | #endif | |
145 | ||
4d5e29a6 | 146 | #ifdef CONFIG_SPI_FLASH_BAR |
cb375185 | 147 | static int spi_flash_write_bar(struct spi_flash *flash, u32 offset) |
4d5e29a6 | 148 | { |
70ccf594 | 149 | u8 cmd, bank_sel; |
4d5e29a6 JT |
150 | int ret; |
151 | ||
70ccf594 JT |
152 | bank_sel = offset / (SPI_FLASH_16MB_BOUN << flash->shift); |
153 | if (bank_sel == flash->bank_curr) | |
154 | goto bar_end; | |
4d5e29a6 JT |
155 | |
156 | cmd = flash->bank_write_cmd; | |
157 | ret = spi_flash_write_common(flash, &cmd, 1, &bank_sel, 1); | |
158 | if (ret < 0) { | |
159 | debug("SF: fail to write bank register\n"); | |
160 | return ret; | |
161 | } | |
6152dd15 | 162 | |
70ccf594 JT |
163 | bar_end: |
164 | flash->bank_curr = bank_sel; | |
165 | return flash->bank_curr; | |
6152dd15 | 166 | } |
0edae52f | 167 | |
cb375185 | 168 | static int spi_flash_read_bar(struct spi_flash *flash, u8 idcode0) |
0edae52f JT |
169 | { |
170 | u8 curr_bank = 0; | |
171 | int ret; | |
172 | ||
173 | if (flash->size <= SPI_FLASH_16MB_BOUN) | |
6f309658 | 174 | goto bar_end; |
0edae52f JT |
175 | |
176 | switch (idcode0) { | |
177 | case SPI_FLASH_CFI_MFR_SPANSION: | |
178 | flash->bank_read_cmd = CMD_BANKADDR_BRRD; | |
179 | flash->bank_write_cmd = CMD_BANKADDR_BRWR; | |
b6a2c436 | 180 | break; |
0edae52f JT |
181 | default: |
182 | flash->bank_read_cmd = CMD_EXTNADDR_RDEAR; | |
183 | flash->bank_write_cmd = CMD_EXTNADDR_WREAR; | |
184 | } | |
185 | ||
186 | ret = spi_flash_read_common(flash, &flash->bank_read_cmd, 1, | |
187 | &curr_bank, 1); | |
188 | if (ret) { | |
189 | debug("SF: fail to read bank addr register\n"); | |
190 | return ret; | |
191 | } | |
192 | ||
6f309658 | 193 | bar_end: |
0edae52f JT |
194 | flash->bank_curr = curr_bank; |
195 | return 0; | |
196 | } | |
4d5e29a6 JT |
197 | #endif |
198 | ||
b902e07c | 199 | #ifdef CONFIG_SF_DUAL_FLASH |
cb375185 | 200 | static void spi_flash_dual(struct spi_flash *flash, u32 *addr) |
f77f4691 | 201 | { |
e228d6de JT |
202 | struct spi_slave *spi = flash->spi; |
203 | ||
f77f4691 JT |
204 | switch (flash->dual_flash) { |
205 | case SF_DUAL_STACKED_FLASH: | |
206 | if (*addr >= (flash->size >> 1)) { | |
207 | *addr -= flash->size >> 1; | |
e228d6de | 208 | spi->flags |= SPI_XFER_U_PAGE; |
f77f4691 | 209 | } else { |
e228d6de | 210 | spi->flags &= ~SPI_XFER_U_PAGE; |
f77f4691 JT |
211 | } |
212 | break; | |
056fbc73 JT |
213 | case SF_DUAL_PARALLEL_FLASH: |
214 | *addr >>= flash->shift; | |
215 | break; | |
f77f4691 JT |
216 | default: |
217 | debug("SF: Unsupported dual_flash=%d\n", flash->dual_flash); | |
218 | break; | |
219 | } | |
220 | } | |
b902e07c | 221 | #endif |
f77f4691 | 222 | |
baaaa753 | 223 | static int spi_flash_sr_ready(struct spi_flash *flash) |
06bc1756 | 224 | { |
4efad20a | 225 | u8 sr; |
baaaa753 JT |
226 | int ret; |
227 | ||
cb375185 | 228 | ret = read_sr(flash, &sr); |
baaaa753 JT |
229 | if (ret < 0) |
230 | return ret; | |
231 | ||
232 | return !(sr & STATUS_WIP); | |
233 | } | |
234 | ||
235 | static int spi_flash_fsr_ready(struct spi_flash *flash) | |
236 | { | |
237 | u8 fsr; | |
238 | int ret; | |
239 | ||
240 | ret = read_fsr(flash, &fsr); | |
241 | if (ret < 0) | |
242 | return ret; | |
243 | ||
244 | return fsr & STATUS_PEC; | |
245 | } | |
246 | ||
247 | static int spi_flash_ready(struct spi_flash *flash) | |
248 | { | |
249 | int sr, fsr; | |
250 | ||
251 | sr = spi_flash_sr_ready(flash); | |
252 | if (sr < 0) | |
253 | return sr; | |
254 | ||
255 | fsr = 1; | |
256 | if (flash->flags & SNOR_F_USE_FSR) { | |
257 | fsr = spi_flash_fsr_ready(flash); | |
258 | if (fsr < 0) | |
259 | return fsr; | |
260 | } | |
261 | ||
262 | return sr && fsr; | |
263 | } | |
264 | ||
6fa40e79 JT |
265 | static int spi_flash_cmd_wait_ready(struct spi_flash *flash, |
266 | unsigned long timeout) | |
baaaa753 | 267 | { |
4efad20a | 268 | int timebase, ret; |
06bc1756 | 269 | |
4efad20a | 270 | timebase = get_timer(0); |
06bc1756 | 271 | |
4efad20a | 272 | while (get_timer(timebase) < timeout) { |
baaaa753 | 273 | ret = spi_flash_ready(flash); |
06bc1756 SDPP |
274 | if (ret < 0) |
275 | return ret; | |
baaaa753 | 276 | if (ret) |
4efad20a | 277 | return 0; |
06bc1756 SDPP |
278 | } |
279 | ||
4efad20a JT |
280 | printf("SF: Timeout!\n"); |
281 | ||
282 | return -ETIMEDOUT; | |
06bc1756 SDPP |
283 | } |
284 | ||
4d5e29a6 JT |
285 | int spi_flash_write_common(struct spi_flash *flash, const u8 *cmd, |
286 | size_t cmd_len, const void *buf, size_t buf_len) | |
287 | { | |
288 | struct spi_slave *spi = flash->spi; | |
289 | unsigned long timeout = SPI_FLASH_PROG_TIMEOUT; | |
290 | int ret; | |
291 | ||
292 | if (buf == NULL) | |
293 | timeout = SPI_FLASH_PAGE_ERASE_TIMEOUT; | |
294 | ||
e228d6de | 295 | ret = spi_claim_bus(spi); |
4d5e29a6 JT |
296 | if (ret) { |
297 | debug("SF: unable to claim SPI bus\n"); | |
298 | return ret; | |
299 | } | |
300 | ||
301 | ret = spi_flash_cmd_write_enable(flash); | |
302 | if (ret < 0) { | |
303 | debug("SF: enabling write failed\n"); | |
304 | return ret; | |
305 | } | |
306 | ||
307 | ret = spi_flash_cmd_write(spi, cmd, cmd_len, buf, buf_len); | |
308 | if (ret < 0) { | |
309 | debug("SF: write cmd failed\n"); | |
310 | return ret; | |
311 | } | |
312 | ||
313 | ret = spi_flash_cmd_wait_ready(flash, timeout); | |
314 | if (ret < 0) { | |
315 | debug("SF: write %s timed out\n", | |
316 | timeout == SPI_FLASH_PROG_TIMEOUT ? | |
317 | "program" : "page erase"); | |
318 | return ret; | |
319 | } | |
320 | ||
321 | spi_release_bus(spi); | |
322 | ||
323 | return ret; | |
324 | } | |
325 | ||
a5e8199a | 326 | int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len) |
4d5e29a6 | 327 | { |
f77f4691 | 328 | u32 erase_size, erase_addr; |
ff063ed4 | 329 | u8 cmd[SPI_FLASH_CMD_LEN]; |
4d5e29a6 JT |
330 | int ret = -1; |
331 | ||
f4f51a8f | 332 | erase_size = flash->erase_size; |
4d5e29a6 JT |
333 | if (offset % erase_size || len % erase_size) { |
334 | debug("SF: Erase offset/length not multiple of erase size\n"); | |
335 | return -1; | |
336 | } | |
337 | ||
439fcb9b BM |
338 | if (flash->flash_is_locked) { |
339 | if (flash->flash_is_locked(flash, offset, len) > 0) { | |
340 | printf("offset 0x%x is protected and cannot be erased\n", | |
341 | offset); | |
342 | return -EINVAL; | |
343 | } | |
c3c016cf FE |
344 | } |
345 | ||
f4f51a8f | 346 | cmd[0] = flash->erase_cmd; |
4d5e29a6 | 347 | while (len) { |
f77f4691 JT |
348 | erase_addr = offset; |
349 | ||
b902e07c | 350 | #ifdef CONFIG_SF_DUAL_FLASH |
f77f4691 | 351 | if (flash->dual_flash > SF_SINGLE_FLASH) |
cb375185 | 352 | spi_flash_dual(flash, &erase_addr); |
b902e07c | 353 | #endif |
4d5e29a6 | 354 | #ifdef CONFIG_SPI_FLASH_BAR |
cb375185 | 355 | ret = spi_flash_write_bar(flash, erase_addr); |
6152dd15 | 356 | if (ret < 0) |
4d5e29a6 | 357 | return ret; |
4d5e29a6 | 358 | #endif |
f77f4691 | 359 | spi_flash_addr(erase_addr, cmd); |
4d5e29a6 JT |
360 | |
361 | debug("SF: erase %2x %2x %2x %2x (%x)\n", cmd[0], cmd[1], | |
f77f4691 | 362 | cmd[2], cmd[3], erase_addr); |
4d5e29a6 JT |
363 | |
364 | ret = spi_flash_write_common(flash, cmd, sizeof(cmd), NULL, 0); | |
365 | if (ret < 0) { | |
366 | debug("SF: erase failed\n"); | |
367 | break; | |
368 | } | |
369 | ||
370 | offset += erase_size; | |
371 | len -= erase_size; | |
372 | } | |
373 | ||
374 | return ret; | |
375 | } | |
376 | ||
a5e8199a | 377 | int spi_flash_cmd_write_ops(struct spi_flash *flash, u32 offset, |
4d5e29a6 JT |
378 | size_t len, const void *buf) |
379 | { | |
e228d6de | 380 | struct spi_slave *spi = flash->spi; |
4d5e29a6 | 381 | unsigned long byte_addr, page_size; |
f77f4691 | 382 | u32 write_addr; |
4d5e29a6 | 383 | size_t chunk_len, actual; |
ff063ed4 | 384 | u8 cmd[SPI_FLASH_CMD_LEN]; |
4d5e29a6 JT |
385 | int ret = -1; |
386 | ||
387 | page_size = flash->page_size; | |
388 | ||
439fcb9b BM |
389 | if (flash->flash_is_locked) { |
390 | if (flash->flash_is_locked(flash, offset, len) > 0) { | |
391 | printf("offset 0x%x is protected and cannot be written\n", | |
392 | offset); | |
393 | return -EINVAL; | |
394 | } | |
c3c016cf FE |
395 | } |
396 | ||
3163aaa6 | 397 | cmd[0] = flash->write_cmd; |
4d5e29a6 | 398 | for (actual = 0; actual < len; actual += chunk_len) { |
f77f4691 JT |
399 | write_addr = offset; |
400 | ||
b902e07c | 401 | #ifdef CONFIG_SF_DUAL_FLASH |
f77f4691 | 402 | if (flash->dual_flash > SF_SINGLE_FLASH) |
cb375185 | 403 | spi_flash_dual(flash, &write_addr); |
b902e07c | 404 | #endif |
4d5e29a6 | 405 | #ifdef CONFIG_SPI_FLASH_BAR |
cb375185 | 406 | ret = spi_flash_write_bar(flash, write_addr); |
6152dd15 | 407 | if (ret < 0) |
4d5e29a6 | 408 | return ret; |
4d5e29a6 JT |
409 | #endif |
410 | byte_addr = offset % page_size; | |
b4141195 | 411 | chunk_len = min(len - actual, (size_t)(page_size - byte_addr)); |
4d5e29a6 | 412 | |
e228d6de | 413 | if (spi->max_write_size) |
b4141195 | 414 | chunk_len = min(chunk_len, |
e228d6de | 415 | (size_t)spi->max_write_size); |
4d5e29a6 | 416 | |
f77f4691 | 417 | spi_flash_addr(write_addr, cmd); |
4d5e29a6 | 418 | |
2ba863fa | 419 | debug("SF: 0x%p => cmd = { 0x%02x 0x%02x%02x%02x } chunk_len = %zu\n", |
4d5e29a6 JT |
420 | buf + actual, cmd[0], cmd[1], cmd[2], cmd[3], chunk_len); |
421 | ||
422 | ret = spi_flash_write_common(flash, cmd, sizeof(cmd), | |
423 | buf + actual, chunk_len); | |
424 | if (ret < 0) { | |
425 | debug("SF: write failed\n"); | |
426 | break; | |
427 | } | |
428 | ||
429 | offset += chunk_len; | |
430 | } | |
431 | ||
432 | return ret; | |
433 | } | |
434 | ||
435 | int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd, | |
436 | size_t cmd_len, void *data, size_t data_len) | |
437 | { | |
438 | struct spi_slave *spi = flash->spi; | |
439 | int ret; | |
440 | ||
e228d6de | 441 | ret = spi_claim_bus(spi); |
4d5e29a6 JT |
442 | if (ret) { |
443 | debug("SF: unable to claim SPI bus\n"); | |
444 | return ret; | |
445 | } | |
446 | ||
447 | ret = spi_flash_cmd_read(spi, cmd, cmd_len, data, data_len); | |
448 | if (ret < 0) { | |
449 | debug("SF: read cmd failed\n"); | |
450 | return ret; | |
451 | } | |
452 | ||
453 | spi_release_bus(spi); | |
454 | ||
455 | return ret; | |
456 | } | |
457 | ||
7bd1c59b M |
458 | /* |
459 | * TODO: remove the weak after all the other spi_flash_copy_mmap | |
460 | * implementations removed from drivers | |
461 | */ | |
146bad96 TR |
462 | void __weak spi_flash_copy_mmap(void *data, void *offset, size_t len) |
463 | { | |
7bd1c59b M |
464 | #ifdef CONFIG_DMA |
465 | if (!dma_memcpy(data, offset, len)) | |
466 | return; | |
467 | #endif | |
146bad96 TR |
468 | memcpy(data, offset, len); |
469 | } | |
470 | ||
a5e8199a | 471 | int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset, |
4d5e29a6 JT |
472 | size_t len, void *data) |
473 | { | |
e228d6de | 474 | struct spi_slave *spi = flash->spi; |
ab92224f | 475 | u8 *cmd, cmdsz; |
f77f4691 | 476 | u32 remain_len, read_len, read_addr; |
ab92224f | 477 | int bank_sel = 0; |
4d5e29a6 JT |
478 | int ret = -1; |
479 | ||
480 | /* Handle memory-mapped SPI */ | |
481 | if (flash->memory_map) { | |
e228d6de | 482 | ret = spi_claim_bus(spi); |
ac5cce38 PS |
483 | if (ret) { |
484 | debug("SF: unable to claim SPI bus\n"); | |
485 | return ret; | |
486 | } | |
e228d6de | 487 | spi_xfer(spi, 0, NULL, NULL, SPI_XFER_MMAP); |
146bad96 | 488 | spi_flash_copy_mmap(data, flash->memory_map + offset, len); |
e228d6de JT |
489 | spi_xfer(spi, 0, NULL, NULL, SPI_XFER_MMAP_END); |
490 | spi_release_bus(spi); | |
4d5e29a6 JT |
491 | return 0; |
492 | } | |
493 | ||
ff063ed4 | 494 | cmdsz = SPI_FLASH_CMD_LEN + flash->dummy_byte; |
c6136aad JT |
495 | cmd = calloc(1, cmdsz); |
496 | if (!cmd) { | |
497 | debug("SF: Failed to allocate cmd\n"); | |
498 | return -ENOMEM; | |
499 | } | |
4d5e29a6 | 500 | |
ff063ed4 | 501 | cmd[0] = flash->read_cmd; |
4d5e29a6 | 502 | while (len) { |
f77f4691 JT |
503 | read_addr = offset; |
504 | ||
b902e07c | 505 | #ifdef CONFIG_SF_DUAL_FLASH |
f77f4691 | 506 | if (flash->dual_flash > SF_SINGLE_FLASH) |
cb375185 | 507 | spi_flash_dual(flash, &read_addr); |
b902e07c | 508 | #endif |
4d5e29a6 | 509 | #ifdef CONFIG_SPI_FLASH_BAR |
cb375185 | 510 | ret = spi_flash_write_bar(flash, read_addr); |
70ccf594 | 511 | if (ret < 0) |
4d5e29a6 | 512 | return ret; |
70ccf594 | 513 | bank_sel = flash->bank_curr; |
4d5e29a6 | 514 | #endif |
056fbc73 JT |
515 | remain_len = ((SPI_FLASH_16MB_BOUN << flash->shift) * |
516 | (bank_sel + 1)) - offset; | |
4d5e29a6 JT |
517 | if (len < remain_len) |
518 | read_len = len; | |
519 | else | |
520 | read_len = remain_len; | |
521 | ||
f77f4691 | 522 | spi_flash_addr(read_addr, cmd); |
4d5e29a6 | 523 | |
ff063ed4 | 524 | ret = spi_flash_read_common(flash, cmd, cmdsz, data, read_len); |
4d5e29a6 JT |
525 | if (ret < 0) { |
526 | debug("SF: read failed\n"); | |
527 | break; | |
528 | } | |
529 | ||
530 | offset += read_len; | |
531 | len -= read_len; | |
532 | data += read_len; | |
533 | } | |
534 | ||
a52a178f | 535 | free(cmd); |
4d5e29a6 JT |
536 | return ret; |
537 | } | |
10ca45d0 JT |
538 | |
539 | #ifdef CONFIG_SPI_FLASH_SST | |
540 | static int sst_byte_write(struct spi_flash *flash, u32 offset, const void *buf) | |
541 | { | |
e228d6de | 542 | struct spi_slave *spi = flash->spi; |
10ca45d0 JT |
543 | int ret; |
544 | u8 cmd[4] = { | |
545 | CMD_SST_BP, | |
546 | offset >> 16, | |
547 | offset >> 8, | |
548 | offset, | |
549 | }; | |
550 | ||
551 | debug("BP[%02x]: 0x%p => cmd = { 0x%02x 0x%06x }\n", | |
e228d6de | 552 | spi_w8r8(spi, CMD_READ_STATUS), buf, cmd[0], offset); |
10ca45d0 JT |
553 | |
554 | ret = spi_flash_cmd_write_enable(flash); | |
555 | if (ret) | |
556 | return ret; | |
557 | ||
e228d6de | 558 | ret = spi_flash_cmd_write(spi, cmd, sizeof(cmd), buf, 1); |
10ca45d0 JT |
559 | if (ret) |
560 | return ret; | |
561 | ||
562 | return spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); | |
563 | } | |
564 | ||
565 | int sst_write_wp(struct spi_flash *flash, u32 offset, size_t len, | |
566 | const void *buf) | |
567 | { | |
e228d6de | 568 | struct spi_slave *spi = flash->spi; |
10ca45d0 JT |
569 | size_t actual, cmd_len; |
570 | int ret; | |
571 | u8 cmd[4]; | |
572 | ||
e228d6de | 573 | ret = spi_claim_bus(spi); |
10ca45d0 JT |
574 | if (ret) { |
575 | debug("SF: Unable to claim SPI bus\n"); | |
576 | return ret; | |
577 | } | |
578 | ||
579 | /* If the data is not word aligned, write out leading single byte */ | |
580 | actual = offset % 2; | |
581 | if (actual) { | |
582 | ret = sst_byte_write(flash, offset, buf); | |
583 | if (ret) | |
584 | goto done; | |
585 | } | |
586 | offset += actual; | |
587 | ||
588 | ret = spi_flash_cmd_write_enable(flash); | |
589 | if (ret) | |
590 | goto done; | |
591 | ||
592 | cmd_len = 4; | |
593 | cmd[0] = CMD_SST_AAI_WP; | |
594 | cmd[1] = offset >> 16; | |
595 | cmd[2] = offset >> 8; | |
596 | cmd[3] = offset; | |
597 | ||
598 | for (; actual < len - 1; actual += 2) { | |
599 | debug("WP[%02x]: 0x%p => cmd = { 0x%02x 0x%06x }\n", | |
e228d6de | 600 | spi_w8r8(spi, CMD_READ_STATUS), buf + actual, |
10ca45d0 JT |
601 | cmd[0], offset); |
602 | ||
e228d6de | 603 | ret = spi_flash_cmd_write(spi, cmd, cmd_len, |
10ca45d0 JT |
604 | buf + actual, 2); |
605 | if (ret) { | |
606 | debug("SF: sst word program failed\n"); | |
607 | break; | |
608 | } | |
609 | ||
610 | ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); | |
611 | if (ret) | |
612 | break; | |
613 | ||
614 | cmd_len = 1; | |
615 | offset += 2; | |
616 | } | |
617 | ||
618 | if (!ret) | |
619 | ret = spi_flash_cmd_write_disable(flash); | |
620 | ||
621 | /* If there is a single trailing byte, write it out */ | |
622 | if (!ret && actual != len) | |
623 | ret = sst_byte_write(flash, offset, buf + actual); | |
624 | ||
625 | done: | |
626 | debug("SF: sst: program %s %zu bytes @ 0x%zx\n", | |
627 | ret ? "failure" : "success", len, offset - actual); | |
628 | ||
e228d6de | 629 | spi_release_bus(spi); |
10ca45d0 JT |
630 | return ret; |
631 | } | |
74c2cee4 BM |
632 | |
633 | int sst_write_bp(struct spi_flash *flash, u32 offset, size_t len, | |
634 | const void *buf) | |
635 | { | |
e228d6de | 636 | struct spi_slave *spi = flash->spi; |
74c2cee4 BM |
637 | size_t actual; |
638 | int ret; | |
639 | ||
e228d6de | 640 | ret = spi_claim_bus(spi); |
74c2cee4 BM |
641 | if (ret) { |
642 | debug("SF: Unable to claim SPI bus\n"); | |
643 | return ret; | |
644 | } | |
645 | ||
646 | for (actual = 0; actual < len; actual++) { | |
647 | ret = sst_byte_write(flash, offset, buf + actual); | |
648 | if (ret) { | |
649 | debug("SF: sst byte program failed\n"); | |
650 | break; | |
651 | } | |
652 | offset++; | |
653 | } | |
654 | ||
655 | if (!ret) | |
656 | ret = spi_flash_cmd_write_disable(flash); | |
657 | ||
658 | debug("SF: sst: program %s %zu bytes @ 0x%zx\n", | |
659 | ret ? "failure" : "success", len, offset - actual); | |
660 | ||
e228d6de | 661 | spi_release_bus(spi); |
74c2cee4 BM |
662 | return ret; |
663 | } | |
10ca45d0 | 664 | #endif |
41b358d7 | 665 | |
5168721e | 666 | #if defined(CONFIG_SPI_FLASH_STMICRO) || defined(CONFIG_SPI_FLASH_SST) |
41b358d7 FE |
667 | static void stm_get_locked_range(struct spi_flash *flash, u8 sr, loff_t *ofs, |
668 | u32 *len) | |
669 | { | |
670 | u8 mask = SR_BP2 | SR_BP1 | SR_BP0; | |
671 | int shift = ffs(mask) - 1; | |
672 | int pow; | |
673 | ||
674 | if (!(sr & mask)) { | |
675 | /* No protection */ | |
676 | *ofs = 0; | |
677 | *len = 0; | |
678 | } else { | |
679 | pow = ((sr & mask) ^ mask) >> shift; | |
680 | *len = flash->size >> pow; | |
681 | *ofs = flash->size - *len; | |
682 | } | |
683 | } | |
684 | ||
685 | /* | |
686 | * Return 1 if the entire region is locked, 0 otherwise | |
687 | */ | |
c3c016cf | 688 | static int stm_is_locked_sr(struct spi_flash *flash, u32 ofs, u32 len, |
41b358d7 FE |
689 | u8 sr) |
690 | { | |
691 | loff_t lock_offs; | |
692 | u32 lock_len; | |
693 | ||
694 | stm_get_locked_range(flash, sr, &lock_offs, &lock_len); | |
695 | ||
696 | return (ofs + len <= lock_offs + lock_len) && (ofs >= lock_offs); | |
697 | } | |
698 | ||
699 | /* | |
700 | * Check if a region of the flash is (completely) locked. See stm_lock() for | |
701 | * more info. | |
702 | * | |
703 | * Returns 1 if entire region is locked, 0 if any portion is unlocked, and | |
704 | * negative on errors. | |
705 | */ | |
c3c016cf | 706 | int stm_is_locked(struct spi_flash *flash, u32 ofs, size_t len) |
41b358d7 FE |
707 | { |
708 | int status; | |
709 | u8 sr; | |
710 | ||
cb375185 | 711 | status = read_sr(flash, &sr); |
41b358d7 FE |
712 | if (status < 0) |
713 | return status; | |
714 | ||
715 | return stm_is_locked_sr(flash, ofs, len, sr); | |
716 | } | |
717 | ||
718 | /* | |
719 | * Lock a region of the flash. Compatible with ST Micro and similar flash. | |
720 | * Supports only the block protection bits BP{0,1,2} in the status register | |
721 | * (SR). Does not support these features found in newer SR bitfields: | |
722 | * - TB: top/bottom protect - only handle TB=0 (top protect) | |
723 | * - SEC: sector/block protect - only handle SEC=0 (block protect) | |
724 | * - CMP: complement protect - only support CMP=0 (range is not complemented) | |
725 | * | |
726 | * Sample table portion for 8MB flash (Winbond w25q64fw): | |
727 | * | |
728 | * SEC | TB | BP2 | BP1 | BP0 | Prot Length | Protected Portion | |
729 | * -------------------------------------------------------------------------- | |
730 | * X | X | 0 | 0 | 0 | NONE | NONE | |
731 | * 0 | 0 | 0 | 0 | 1 | 128 KB | Upper 1/64 | |
732 | * 0 | 0 | 0 | 1 | 0 | 256 KB | Upper 1/32 | |
733 | * 0 | 0 | 0 | 1 | 1 | 512 KB | Upper 1/16 | |
734 | * 0 | 0 | 1 | 0 | 0 | 1 MB | Upper 1/8 | |
735 | * 0 | 0 | 1 | 0 | 1 | 2 MB | Upper 1/4 | |
736 | * 0 | 0 | 1 | 1 | 0 | 4 MB | Upper 1/2 | |
737 | * X | X | 1 | 1 | 1 | 8 MB | ALL | |
738 | * | |
739 | * Returns negative on errors, 0 on success. | |
740 | */ | |
741 | int stm_lock(struct spi_flash *flash, u32 ofs, size_t len) | |
742 | { | |
743 | u8 status_old, status_new; | |
744 | u8 mask = SR_BP2 | SR_BP1 | SR_BP0; | |
745 | u8 shift = ffs(mask) - 1, pow, val; | |
a668a164 | 746 | int ret; |
41b358d7 | 747 | |
cb375185 | 748 | ret = read_sr(flash, &status_old); |
a668a164 FE |
749 | if (ret < 0) |
750 | return ret; | |
41b358d7 FE |
751 | |
752 | /* SPI NOR always locks to the end */ | |
753 | if (ofs + len != flash->size) { | |
754 | /* Does combined region extend to end? */ | |
755 | if (!stm_is_locked_sr(flash, ofs + len, flash->size - ofs - len, | |
756 | status_old)) | |
757 | return -EINVAL; | |
758 | len = flash->size - ofs; | |
759 | } | |
760 | ||
761 | /* | |
762 | * Need smallest pow such that: | |
763 | * | |
764 | * 1 / (2^pow) <= (len / size) | |
765 | * | |
766 | * so (assuming power-of-2 size) we do: | |
767 | * | |
768 | * pow = ceil(log2(size / len)) = log2(size) - floor(log2(len)) | |
769 | */ | |
770 | pow = ilog2(flash->size) - ilog2(len); | |
771 | val = mask - (pow << shift); | |
772 | if (val & ~mask) | |
773 | return -EINVAL; | |
774 | ||
775 | /* Don't "lock" with no region! */ | |
776 | if (!(val & mask)) | |
777 | return -EINVAL; | |
778 | ||
779 | status_new = (status_old & ~mask) | val; | |
780 | ||
781 | /* Only modify protection if it will not unlock other areas */ | |
782 | if ((status_new & mask) <= (status_old & mask)) | |
783 | return -EINVAL; | |
784 | ||
cb375185 | 785 | write_sr(flash, status_new); |
41b358d7 FE |
786 | |
787 | return 0; | |
788 | } | |
789 | ||
790 | /* | |
791 | * Unlock a region of the flash. See stm_lock() for more info | |
792 | * | |
793 | * Returns negative on errors, 0 on success. | |
794 | */ | |
795 | int stm_unlock(struct spi_flash *flash, u32 ofs, size_t len) | |
796 | { | |
797 | uint8_t status_old, status_new; | |
798 | u8 mask = SR_BP2 | SR_BP1 | SR_BP0; | |
799 | u8 shift = ffs(mask) - 1, pow, val; | |
a668a164 | 800 | int ret; |
41b358d7 | 801 | |
cb375185 | 802 | ret = read_sr(flash, &status_old); |
a668a164 FE |
803 | if (ret < 0) |
804 | return ret; | |
41b358d7 FE |
805 | |
806 | /* Cannot unlock; would unlock larger region than requested */ | |
50921583 FE |
807 | if (stm_is_locked_sr(flash, ofs - flash->erase_size, flash->erase_size, |
808 | status_old)) | |
41b358d7 FE |
809 | return -EINVAL; |
810 | /* | |
811 | * Need largest pow such that: | |
812 | * | |
813 | * 1 / (2^pow) >= (len / size) | |
814 | * | |
815 | * so (assuming power-of-2 size) we do: | |
816 | * | |
817 | * pow = floor(log2(size / len)) = log2(size) - ceil(log2(len)) | |
818 | */ | |
819 | pow = ilog2(flash->size) - order_base_2(flash->size - (ofs + len)); | |
820 | if (ofs + len == flash->size) { | |
821 | val = 0; /* fully unlocked */ | |
822 | } else { | |
823 | val = mask - (pow << shift); | |
824 | /* Some power-of-two sizes are not supported */ | |
825 | if (val & ~mask) | |
826 | return -EINVAL; | |
827 | } | |
828 | ||
829 | status_new = (status_old & ~mask) | val; | |
830 | ||
831 | /* Only modify protection if it will not lock other areas */ | |
832 | if ((status_new & mask) >= (status_old & mask)) | |
833 | return -EINVAL; | |
834 | ||
cb375185 | 835 | write_sr(flash, status_new); |
41b358d7 FE |
836 | |
837 | return 0; | |
838 | } | |
5168721e | 839 | #endif |
3847c0c1 JT |
840 | |
841 | ||
3847c0c1 | 842 | #ifdef CONFIG_SPI_FLASH_MACRONIX |
9275929c | 843 | static int macronix_quad_enable(struct spi_flash *flash) |
3847c0c1 JT |
844 | { |
845 | u8 qeb_status; | |
846 | int ret; | |
847 | ||
cb375185 | 848 | ret = read_sr(flash, &qeb_status); |
3847c0c1 JT |
849 | if (ret < 0) |
850 | return ret; | |
851 | ||
bfcdc395 JT |
852 | if (qeb_status & STATUS_QEB_MXIC) |
853 | return 0; | |
854 | ||
d9a0ab6c | 855 | ret = write_sr(flash, qeb_status | STATUS_QEB_MXIC); |
bfcdc395 JT |
856 | if (ret < 0) |
857 | return ret; | |
858 | ||
859 | /* read SR and check it */ | |
860 | ret = read_sr(flash, &qeb_status); | |
861 | if (!(ret >= 0 && (qeb_status & STATUS_QEB_MXIC))) { | |
862 | printf("SF: Macronix SR Quad bit not clear\n"); | |
863 | return -EINVAL; | |
3847c0c1 JT |
864 | } |
865 | ||
866 | return ret; | |
867 | } | |
868 | #endif | |
869 | ||
870 | #if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND) | |
9275929c | 871 | static int spansion_quad_enable(struct spi_flash *flash) |
3847c0c1 JT |
872 | { |
873 | u8 qeb_status; | |
874 | int ret; | |
875 | ||
cb375185 | 876 | ret = read_cr(flash, &qeb_status); |
3847c0c1 JT |
877 | if (ret < 0) |
878 | return ret; | |
879 | ||
ffecb0fc JT |
880 | if (qeb_status & STATUS_QEB_WINSPAN) |
881 | return 0; | |
882 | ||
d9a0ab6c | 883 | ret = write_cr(flash, qeb_status | STATUS_QEB_WINSPAN); |
ffecb0fc JT |
884 | if (ret < 0) |
885 | return ret; | |
886 | ||
887 | /* read CR and check it */ | |
888 | ret = read_cr(flash, &qeb_status); | |
889 | if (!(ret >= 0 && (qeb_status & STATUS_QEB_WINSPAN))) { | |
890 | printf("SF: Spansion CR Quad bit not clear\n"); | |
891 | return -EINVAL; | |
3847c0c1 JT |
892 | } |
893 | ||
894 | return ret; | |
895 | } | |
896 | #endif | |
897 | ||
c56ae751 JT |
898 | #ifdef CONFIG_SPI_FLASH_STMICRO |
899 | static int micron_quad_enable(struct spi_flash *flash) | |
900 | { | |
901 | u8 qeb_status; | |
902 | int ret; | |
903 | ||
904 | ret = read_evcr(flash, &qeb_status); | |
905 | if (ret < 0) | |
906 | return ret; | |
907 | ||
908 | if (!(qeb_status & STATUS_QEB_MICRON)) | |
909 | return 0; | |
910 | ||
911 | ret = write_evcr(flash, qeb_status & ~STATUS_QEB_MICRON); | |
912 | if (ret < 0) | |
913 | return ret; | |
914 | ||
915 | /* read EVCR and check it */ | |
916 | ret = read_evcr(flash, &qeb_status); | |
917 | if (!(ret >= 0 && !(qeb_status & STATUS_QEB_MICRON))) { | |
918 | printf("SF: Micron EVCR Quad bit not clear\n"); | |
919 | return -EINVAL; | |
920 | } | |
921 | ||
922 | return ret; | |
923 | } | |
924 | #endif | |
925 | ||
9275929c | 926 | static int set_quad_mode(struct spi_flash *flash, u8 idcode0) |
3847c0c1 JT |
927 | { |
928 | switch (idcode0) { | |
929 | #ifdef CONFIG_SPI_FLASH_MACRONIX | |
930 | case SPI_FLASH_CFI_MFR_MACRONIX: | |
9275929c | 931 | return macronix_quad_enable(flash); |
3847c0c1 JT |
932 | #endif |
933 | #if defined(CONFIG_SPI_FLASH_SPANSION) || defined(CONFIG_SPI_FLASH_WINBOND) | |
934 | case SPI_FLASH_CFI_MFR_SPANSION: | |
935 | case SPI_FLASH_CFI_MFR_WINBOND: | |
9275929c | 936 | return spansion_quad_enable(flash); |
3847c0c1 JT |
937 | #endif |
938 | #ifdef CONFIG_SPI_FLASH_STMICRO | |
939 | case SPI_FLASH_CFI_MFR_STMICRO: | |
c56ae751 | 940 | return micron_quad_enable(flash); |
3847c0c1 JT |
941 | #endif |
942 | default: | |
943 | printf("SF: Need set QEB func for %02x flash\n", idcode0); | |
944 | return -1; | |
945 | } | |
946 | } | |
947 | ||
3847c0c1 JT |
948 | #if CONFIG_IS_ENABLED(OF_CONTROL) |
949 | int spi_flash_decode_fdt(const void *blob, struct spi_flash *flash) | |
950 | { | |
d178a1c5 | 951 | #ifdef CONFIG_DM_SPI_FLASH |
3847c0c1 JT |
952 | fdt_addr_t addr; |
953 | fdt_size_t size; | |
d178a1c5 | 954 | int node = flash->dev->of_offset; |
3847c0c1 JT |
955 | |
956 | addr = fdtdec_get_addr_size(blob, node, "memory-map", &size); | |
957 | if (addr == FDT_ADDR_T_NONE) { | |
958 | debug("%s: Cannot decode address\n", __func__); | |
959 | return 0; | |
960 | } | |
961 | ||
962 | if (flash->size != size) { | |
963 | debug("%s: Memory map must cover entire device\n", __func__); | |
964 | return -1; | |
965 | } | |
966 | flash->memory_map = map_sysmem(addr, size); | |
d178a1c5 | 967 | #endif |
3847c0c1 JT |
968 | |
969 | return 0; | |
970 | } | |
971 | #endif /* CONFIG_IS_ENABLED(OF_CONTROL) */ | |
972 | ||
bfdb07eb | 973 | int spi_flash_scan(struct spi_flash *flash) |
3847c0c1 | 974 | { |
bfdb07eb | 975 | struct spi_slave *spi = flash->spi; |
3847c0c1 | 976 | const struct spi_flash_params *params; |
1e90d9fd | 977 | u16 jedec, ext_jedec; |
d25dd942 | 978 | u8 cmd, idcode[5]; |
3847c0c1 | 979 | int ret; |
d25dd942 JT |
980 | static u8 spi_read_cmds_array[] = { |
981 | CMD_READ_ARRAY_SLOW, | |
982 | CMD_READ_ARRAY_FAST, | |
983 | CMD_READ_DUAL_OUTPUT_FAST, | |
d25dd942 | 984 | CMD_READ_QUAD_OUTPUT_FAST, |
1c17f5ec | 985 | CMD_READ_DUAL_IO_FAST, |
d25dd942 | 986 | CMD_READ_QUAD_IO_FAST }; |
3847c0c1 | 987 | |
1e90d9fd JT |
988 | /* Read the ID codes */ |
989 | ret = spi_flash_cmd(spi, CMD_READ_ID, idcode, sizeof(idcode)); | |
990 | if (ret) { | |
991 | printf("SF: Failed to get idcodes\n"); | |
0badb23d | 992 | return ret; |
1e90d9fd JT |
993 | } |
994 | ||
995 | #ifdef DEBUG | |
996 | printf("SF: Got idcodes\n"); | |
997 | print_buffer(0, idcode, 1, sizeof(idcode), 0); | |
998 | #endif | |
999 | ||
1000 | jedec = idcode[1] << 8 | idcode[2]; | |
1001 | ext_jedec = idcode[3] << 8 | idcode[4]; | |
1002 | ||
3847c0c1 JT |
1003 | /* Validate params from spi_flash_params table */ |
1004 | params = spi_flash_params_table; | |
1005 | for (; params->name != NULL; params++) { | |
1006 | if ((params->jedec >> 16) == idcode[0]) { | |
1007 | if ((params->jedec & 0xFFFF) == jedec) { | |
1008 | if (params->ext_jedec == 0) | |
1009 | break; | |
1010 | else if (params->ext_jedec == ext_jedec) | |
1011 | break; | |
1012 | } | |
1013 | } | |
1014 | } | |
1015 | ||
1016 | if (!params->name) { | |
1017 | printf("SF: Unsupported flash IDs: "); | |
1018 | printf("manuf %02x, jedec %04x, ext_jedec %04x\n", | |
1019 | idcode[0], jedec, ext_jedec); | |
1020 | return -EPROTONOSUPPORT; | |
1021 | } | |
1022 | ||
1023 | /* Flash powers up read-only, so clear BP# bits */ | |
6f9d670d JT |
1024 | if (idcode[0] == SPI_FLASH_CFI_MFR_ATMEL || |
1025 | idcode[0] == SPI_FLASH_CFI_MFR_MACRONIX || | |
1026 | idcode[0] == SPI_FLASH_CFI_MFR_SST) | |
cb375185 | 1027 | write_sr(flash, 0); |
3847c0c1 JT |
1028 | |
1029 | /* Assign spi data */ | |
3847c0c1 JT |
1030 | flash->name = params->name; |
1031 | flash->memory_map = spi->memory_map; | |
e228d6de | 1032 | flash->dual_flash = spi->option; |
3847c0c1 JT |
1033 | |
1034 | /* Assign spi flash flags */ | |
1035 | if (params->flags & SST_WR) | |
1036 | flash->flags |= SNOR_F_SST_WR; | |
1037 | ||
1038 | /* Assign spi_flash ops */ | |
1039 | #ifndef CONFIG_DM_SPI_FLASH | |
1040 | flash->write = spi_flash_cmd_write_ops; | |
1041 | #if defined(CONFIG_SPI_FLASH_SST) | |
1042 | if (flash->flags & SNOR_F_SST_WR) { | |
cdf33938 | 1043 | if (spi->mode & SPI_TX_BYTE) |
3847c0c1 JT |
1044 | flash->write = sst_write_bp; |
1045 | else | |
1046 | flash->write = sst_write_wp; | |
1047 | } | |
1048 | #endif | |
1049 | flash->erase = spi_flash_cmd_erase_ops; | |
1050 | flash->read = spi_flash_cmd_read_ops; | |
1051 | #endif | |
1052 | ||
1053 | /* lock hooks are flash specific - assign them based on idcode0 */ | |
1054 | switch (idcode[0]) { | |
1055 | #if defined(CONFIG_SPI_FLASH_STMICRO) || defined(CONFIG_SPI_FLASH_SST) | |
1056 | case SPI_FLASH_CFI_MFR_STMICRO: | |
1057 | case SPI_FLASH_CFI_MFR_SST: | |
1058 | flash->flash_lock = stm_lock; | |
1059 | flash->flash_unlock = stm_unlock; | |
1060 | flash->flash_is_locked = stm_is_locked; | |
1061 | #endif | |
1062 | break; | |
1063 | default: | |
1064 | debug("SF: Lock ops not supported for %02x flash\n", idcode[0]); | |
1065 | } | |
1066 | ||
1067 | /* Compute the flash size */ | |
1068 | flash->shift = (flash->dual_flash & SF_DUAL_PARALLEL_FLASH) ? 1 : 0; | |
1069 | /* | |
1070 | * The Spansion S25FL032P and S25FL064P have 256b pages, yet use the | |
1071 | * 0x4d00 Extended JEDEC code. The rest of the Spansion flashes with | |
1072 | * the 0x4d00 Extended JEDEC code have 512b pages. All of the others | |
1073 | * have 256b pages. | |
1074 | */ | |
1075 | if (ext_jedec == 0x4d00) { | |
1076 | if ((jedec == 0x0215) || (jedec == 0x216)) | |
1077 | flash->page_size = 256; | |
1078 | else | |
1079 | flash->page_size = 512; | |
1080 | } else { | |
1081 | flash->page_size = 256; | |
1082 | } | |
1083 | flash->page_size <<= flash->shift; | |
1084 | flash->sector_size = params->sector_size << flash->shift; | |
1085 | flash->size = flash->sector_size * params->nr_sectors << flash->shift; | |
1086 | #ifdef CONFIG_SF_DUAL_FLASH | |
1087 | if (flash->dual_flash & SF_DUAL_STACKED_FLASH) | |
1088 | flash->size <<= 1; | |
1089 | #endif | |
1090 | ||
1091 | /* Compute erase sector and command */ | |
1092 | if (params->flags & SECT_4K) { | |
1093 | flash->erase_cmd = CMD_ERASE_4K; | |
1094 | flash->erase_size = 4096 << flash->shift; | |
1095 | } else if (params->flags & SECT_32K) { | |
1096 | flash->erase_cmd = CMD_ERASE_32K; | |
1097 | flash->erase_size = 32768 << flash->shift; | |
1098 | } else { | |
1099 | flash->erase_cmd = CMD_ERASE_64K; | |
1100 | flash->erase_size = flash->sector_size; | |
1101 | } | |
1102 | ||
1103 | /* Now erase size becomes valid sector size */ | |
1104 | flash->sector_size = flash->erase_size; | |
1105 | ||
1106 | /* Look for the fastest read cmd */ | |
91292e0b | 1107 | cmd = fls(params->e_rd_cmd & spi->mode_rx); |
3847c0c1 JT |
1108 | if (cmd) { |
1109 | cmd = spi_read_cmds_array[cmd - 1]; | |
1110 | flash->read_cmd = cmd; | |
1111 | } else { | |
1112 | /* Go for default supported read cmd */ | |
1113 | flash->read_cmd = CMD_READ_ARRAY_FAST; | |
1114 | } | |
1115 | ||
1116 | /* Not require to look for fastest only two write cmds yet */ | |
cdf33938 | 1117 | if (params->flags & WR_QPP && spi->mode & SPI_TX_QUAD) |
3847c0c1 JT |
1118 | flash->write_cmd = CMD_QUAD_PAGE_PROGRAM; |
1119 | else | |
1120 | /* Go for default supported write cmd */ | |
1121 | flash->write_cmd = CMD_PAGE_PROGRAM; | |
1122 | ||
1123 | /* Set the quad enable bit - only for quad commands */ | |
1124 | if ((flash->read_cmd == CMD_READ_QUAD_OUTPUT_FAST) || | |
1125 | (flash->read_cmd == CMD_READ_QUAD_IO_FAST) || | |
1126 | (flash->write_cmd == CMD_QUAD_PAGE_PROGRAM)) { | |
9275929c | 1127 | ret = set_quad_mode(flash, idcode[0]); |
3847c0c1 JT |
1128 | if (ret) { |
1129 | debug("SF: Fail to set QEB for %02x\n", idcode[0]); | |
1130 | return -EINVAL; | |
1131 | } | |
1132 | } | |
1133 | ||
1134 | /* Read dummy_byte: dummy byte is determined based on the | |
1135 | * dummy cycles of a particular command. | |
1136 | * Fast commands - dummy_byte = dummy_cycles/8 | |
1137 | * I/O commands- dummy_byte = (dummy_cycles * no.of lines)/8 | |
1138 | * For I/O commands except cmd[0] everything goes on no.of lines | |
1139 | * based on particular command but incase of fast commands except | |
1140 | * data all go on single line irrespective of command. | |
1141 | */ | |
1142 | switch (flash->read_cmd) { | |
1143 | case CMD_READ_QUAD_IO_FAST: | |
1144 | flash->dummy_byte = 2; | |
1145 | break; | |
1146 | case CMD_READ_ARRAY_SLOW: | |
1147 | flash->dummy_byte = 0; | |
1148 | break; | |
1149 | default: | |
1150 | flash->dummy_byte = 1; | |
1151 | } | |
1152 | ||
1153 | #ifdef CONFIG_SPI_FLASH_STMICRO | |
1154 | if (params->flags & E_FSR) | |
1155 | flash->flags |= SNOR_F_USE_FSR; | |
1156 | #endif | |
1157 | ||
1158 | /* Configure the BAR - discover bank cmds and read current bank */ | |
1159 | #ifdef CONFIG_SPI_FLASH_BAR | |
cb375185 | 1160 | ret = spi_flash_read_bar(flash, idcode[0]); |
3847c0c1 JT |
1161 | if (ret < 0) |
1162 | return ret; | |
1163 | #endif | |
1164 | ||
1165 | #if CONFIG_IS_ENABLED(OF_CONTROL) | |
1166 | ret = spi_flash_decode_fdt(gd->fdt_blob, flash); | |
1167 | if (ret) { | |
1168 | debug("SF: FDT decode error\n"); | |
1169 | return -EINVAL; | |
1170 | } | |
1171 | #endif | |
1172 | ||
1173 | #ifndef CONFIG_SPL_BUILD | |
1174 | printf("SF: Detected %s with page size ", flash->name); | |
1175 | print_size(flash->page_size, ", erase size "); | |
1176 | print_size(flash->erase_size, ", total "); | |
1177 | print_size(flash->size, ""); | |
1178 | if (flash->memory_map) | |
1179 | printf(", mapped at %p", flash->memory_map); | |
1180 | puts("\n"); | |
1181 | #endif | |
1182 | ||
1183 | #ifndef CONFIG_SPI_FLASH_BAR | |
1184 | if (((flash->dual_flash == SF_SINGLE_FLASH) && | |
1185 | (flash->size > SPI_FLASH_16MB_BOUN)) || | |
1186 | ((flash->dual_flash > SF_SINGLE_FLASH) && | |
1187 | (flash->size > SPI_FLASH_16MB_BOUN << 1))) { | |
1188 | puts("SF: Warning - Only lower 16MiB accessible,"); | |
1189 | puts(" Full access #define CONFIG_SPI_FLASH_BAR\n"); | |
1190 | } | |
1191 | #endif | |
1192 | ||
1193 | return ret; | |
1194 | } |