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