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