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