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