blob: bfd585b2dad3ffc728a812c624f01b80b1e479af [file] [log] [blame]
David Hendricks398714f2014-07-03 17:49:41 -07001/*
2 * This file is part of the flashrom project.
3 *
4 * Copyright (C) 2014 Google Inc.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 *
13 * Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * Neither the name of Google or the names of contributors or
18 * licensors may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 *
21 * This software is provided "AS IS," without a warranty of any kind.
22 * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
23 * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
24 * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
25 * GOOGLE INC AND ITS LICENSORS SHALL NOT BE LIABLE
26 * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
27 * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
28 * GOOGLE OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
29 * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
30 * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
31 * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
32 * EVEN IF GOOGLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
Nikolai Artemiev144243b2020-11-10 11:57:39 +110033 */
34
35/*
David Hendricks43d9afd2015-03-13 20:54:23 -070036 * s25f.c - Helper functions for Spansion S25FL and S25FS SPI flash chips.
Vadim Bendebury3a501162014-10-21 20:38:13 -070037 * Uses 24 bit addressing for the FS chips and 32 bit addressing for the FL
38 * chips (which is required by the overlayed sector size devices).
39 * TODO: Implement fancy hybrid sector architecture helpers.
David Hendricks398714f2014-07-03 17:49:41 -070040 */
41
Vadim Bendebury3a501162014-10-21 20:38:13 -070042#include <string.h>
43
David Hendricks398714f2014-07-03 17:49:41 -070044#include "chipdrivers.h"
Mayur Panchalf4796862019-08-05 15:46:12 +100045#include "hwaccess.h"
David Hendricks398714f2014-07-03 17:49:41 -070046#include "spi.h"
David Hendricks43d9afd2015-03-13 20:54:23 -070047#include "writeprotect.h"
David Hendricks398714f2014-07-03 17:49:41 -070048
David Hendricks43d9afd2015-03-13 20:54:23 -070049/*
50 * RDAR and WRAR are supported on chips which have more than one set of status
51 * and control registers and take an address of the register to read/write.
52 * WRR, RDSR2, and RDCR are used on chips with a more limited set of control/
53 * status registers.
54 *
55 * WRR is somewhat peculiar. It shares the same opcode as JEDEC_WRSR, and if
56 * given one data byte (following the opcode) it acts the same way. If it's
57 * given two data bytes, the first data byte overwrites status register 1
58 * and the second data byte overwrites config register 1.
59 */
60#define CMD_WRR 0x01
61#define CMD_WRDI 0x04
62#define CMD_RDSR2 0x07 /* note: read SR1 with JEDEC RDSR opcode */
63#define CMD_RDCR 0x35
David Hendricks398714f2014-07-03 17:49:41 -070064#define CMD_RDAR 0x65
65#define CMD_WRAR 0x71
David Hendricks43d9afd2015-03-13 20:54:23 -070066
67/* TODO: For now, commands which use an address assume 24-bit addressing */
68#define CMD_WRR_LEN 3
69#define CMD_WRDI_LEN 1
David Hendricks398714f2014-07-03 17:49:41 -070070#define CMD_RDAR_LEN 4
71#define CMD_WRAR_LEN 5
72
73#define CMD_RSTEN 0x66
74#define CMD_RST 0x99
75
David Hendricksa9884852014-12-11 15:31:12 -080076#define CR1NV_ADDR 0x000002
David Hendricks43d9afd2015-03-13 20:54:23 -070077#define CR1_BPNV_O (1 << 3)
78#define CR1_TBPROT_O (1 << 5)
David Hendricks398714f2014-07-03 17:49:41 -070079#define CR3NV_ADDR 0x000004
80#define CR3NV_20H_NV (1 << 3)
81
David Hendricks43d9afd2015-03-13 20:54:23 -070082/* See "Embedded Algorithm Performance Tables for additional timing specs. */
83#define T_W 145 * 1000 /* NV register write time (145ms) */
84#define T_RPH 35 /* Reset pulse hold time (35us) */
85#define S25FS_T_SE 145 * 1000 /* Sector Erase Time (145ms) */
86#define S25FL_T_SE 130 * 1000 /* Sector Erase Time (130ms) */
87
Souvik Ghoshd75cd672016-06-17 14:21:39 -070088static int s25f_legacy_software_reset(const struct flashctx *flash)
David Hendricks43d9afd2015-03-13 20:54:23 -070089{
90 int result;
91 struct spi_command cmds[] = {
92 {
93 .writecnt = 1,
94 .writearr = (const unsigned char[]){ CMD_RSTEN },
95 .readcnt = 0,
96 .readarr = NULL,
97 }, {
98 .writecnt = 1,
99 .writearr = (const unsigned char[]){ 0xf0 },
100 .readcnt = 0,
101 .readarr = NULL,
102 }, {
103 .writecnt = 0,
104 .writearr = NULL,
105 .readcnt = 0,
106 .readarr = NULL,
107 }};
108
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700109 result = spi_send_multicommand(flash, cmds);
David Hendricks43d9afd2015-03-13 20:54:23 -0700110 if (result) {
111 msg_cerr("%s failed during command execution\n", __func__);
112 return result;
113 }
114
115 /* Allow time for reset command to execute. The datasheet specifies
116 * Trph = 35us, double that to be safe. */
117 programmer_delay(T_RPH * 2);
118
119 return 0;
120}
121
122/* "Legacy software reset" is disabled by default on S25FS, use this instead. */
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700123static int s25fs_software_reset(struct flashctx *flash)
David Hendricks43d9afd2015-03-13 20:54:23 -0700124{
125 int result;
126 struct spi_command cmds[] = {
127 {
128 .writecnt = 1,
129 .writearr = (const unsigned char[]){ CMD_RSTEN },
130 .readcnt = 0,
131 .readarr = NULL,
132 }, {
133 .writecnt = 1,
134 .writearr = (const unsigned char[]){ CMD_RST },
135 .readcnt = 0,
136 .readarr = NULL,
137 }, {
138 .writecnt = 0,
139 .writearr = NULL,
140 .readcnt = 0,
141 .readarr = NULL,
142 }};
143
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700144 result = spi_send_multicommand(flash, cmds);
David Hendricks43d9afd2015-03-13 20:54:23 -0700145 if (result) {
146 msg_cerr("%s failed during command execution\n", __func__);
147 return result;
148 }
149
150 /* Allow time for reset command to execute. Double tRPH to be safe. */
151 programmer_delay(T_RPH * 2);
152
153 return 0;
154}
155
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700156static int s25f_poll_status(const struct flashctx *flash)
David Hendricks43d9afd2015-03-13 20:54:23 -0700157{
Ramya Vijaykumar4af3f822016-01-27 11:51:27 +0530158 uint8_t tmp = spi_read_status_register(flash);
David Hendricks43d9afd2015-03-13 20:54:23 -0700159
Edward O'Callaghan8b5e4732019-03-05 15:27:53 +1100160 while (tmp & SPI_SR_WIP) {
David Hendricks43d9afd2015-03-13 20:54:23 -0700161 /*
162 * The WIP bit on S25F chips remains set to 1 if erase or
163 * programming errors occur, so we must check for those
164 * errors here. If an error is encountered, do a software
165 * reset to clear WIP and other volatile bits, otherwise
166 * the chip will be unresponsive to further commands.
167 */
Edward O'Callaghan1945f1e2019-03-18 13:12:51 +1100168 if (tmp & SPI_SR_ERA_ERR) {
David Hendricks43d9afd2015-03-13 20:54:23 -0700169 msg_cerr("Erase error occurred\n");
170 s25f_legacy_software_reset(flash);
171 return -1;
172 }
173
174 if (tmp & (1 << 6)) {
175 msg_cerr("Programming error occurred\n");
176 s25f_legacy_software_reset(flash);
177 return -1;
178 }
179
180 programmer_delay(1000 * 10);
Ramya Vijaykumar4af3f822016-01-27 11:51:27 +0530181 tmp = spi_read_status_register(flash);
David Hendricks43d9afd2015-03-13 20:54:23 -0700182 }
183
184 return 0;
185}
186
187/* "Read Any Register" instruction only supported on S25FS */
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700188static int s25fs_read_cr(const struct flashctx *flash, uint32_t addr)
David Hendricks398714f2014-07-03 17:49:41 -0700189{
190 int result;
191 uint8_t cfg;
192 /* By default, 8 dummy cycles are necessary for variable-latency
193 commands such as RDAR (see CR2NV[3:0]). */
194 unsigned char read_cr_cmd[] = {
Nikolai Artemiev144243b2020-11-10 11:57:39 +1100195 CMD_RDAR,
196 (addr >> 16) & 0xff,
197 (addr >> 8) & 0xff,
198 (addr & 0xff),
199 0x00, 0x00, 0x00, 0x00,
200 0x00, 0x00, 0x00, 0x00,
David Hendricks398714f2014-07-03 17:49:41 -0700201 };
202
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700203 result = spi_send_command(flash, sizeof(read_cr_cmd), 1, read_cr_cmd, &cfg);
David Hendricks398714f2014-07-03 17:49:41 -0700204 if (result) {
205 msg_cerr("%s failed during command execution at address 0x%x\n",
206 __func__, addr);
David Hendricks688b5e22014-12-12 11:15:44 -0800207 return -1;
David Hendricks398714f2014-07-03 17:49:41 -0700208 }
209
210 return cfg;
211}
212
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700213static int s25f_read_cr1(const struct flashctx *flash)
David Hendricks43d9afd2015-03-13 20:54:23 -0700214{
215 int result;
216 uint8_t cfg;
217 unsigned char read_cr_cmd[] = { CMD_RDCR };
218
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700219 result = spi_send_command(flash, sizeof(read_cr_cmd), 1, read_cr_cmd, &cfg);
David Hendricks43d9afd2015-03-13 20:54:23 -0700220 if (result) {
221 msg_cerr("%s failed during command execution\n", __func__);
222 return -1;
223 }
224
225 return cfg;
226}
227
228/* "Write Any Register" instruction only supported on S25FS */
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700229static int s25fs_write_cr(const struct flashctx *flash,
David Hendricks43d9afd2015-03-13 20:54:23 -0700230 uint32_t addr, uint8_t data)
David Hendricks398714f2014-07-03 17:49:41 -0700231{
232 int result;
233 struct spi_command cmds[] = {
234 {
235 .writecnt = JEDEC_WREN_OUTSIZE,
236 .writearr = (const unsigned char[]){ JEDEC_WREN },
237 .readcnt = 0,
238 .readarr = NULL,
239 }, {
240 .writecnt = CMD_WRAR_LEN,
241 .writearr = (const unsigned char[]){
242 CMD_WRAR,
243 (addr >> 16) & 0xff,
244 (addr >> 8) & 0xff,
245 (addr & 0xff),
246 data
247 },
248 .readcnt = 0,
249 .readarr = NULL,
250 }, {
251 .writecnt = 0,
252 .writearr = NULL,
253 .readcnt = 0,
254 .readarr = NULL,
255 }};
256
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700257 result = spi_send_multicommand(flash, cmds);
David Hendricks398714f2014-07-03 17:49:41 -0700258 if (result) {
259 msg_cerr("%s failed during command execution at address 0x%x\n",
260 __func__, addr);
David Hendricks688b5e22014-12-12 11:15:44 -0800261 return -1;
David Hendricks398714f2014-07-03 17:49:41 -0700262 }
263
David Hendricks43d9afd2015-03-13 20:54:23 -0700264 programmer_delay(T_W);
265 return s25f_poll_status(flash);
David Hendricks398714f2014-07-03 17:49:41 -0700266}
267
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700268static int s25f_write_cr1(const struct flashctx *flash, uint8_t data)
David Hendricks398714f2014-07-03 17:49:41 -0700269{
270 int result;
271 struct spi_command cmds[] = {
272 {
David Hendricks43d9afd2015-03-13 20:54:23 -0700273 .writecnt = JEDEC_WREN_OUTSIZE,
274 .writearr = (const unsigned char[]){ JEDEC_WREN },
David Hendricks398714f2014-07-03 17:49:41 -0700275 .readcnt = 0,
276 .readarr = NULL,
277 }, {
David Hendricks43d9afd2015-03-13 20:54:23 -0700278 .writecnt = CMD_WRR_LEN,
279 .writearr = (const unsigned char[]){
280 CMD_WRR,
Ramya Vijaykumar4af3f822016-01-27 11:51:27 +0530281 spi_read_status_register(flash),
David Hendricks43d9afd2015-03-13 20:54:23 -0700282 data,
283 },
David Hendricks398714f2014-07-03 17:49:41 -0700284 .readcnt = 0,
285 .readarr = NULL,
286 }, {
287 .writecnt = 0,
288 .writearr = NULL,
289 .readcnt = 0,
290 .readarr = NULL,
291 }};
292
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700293 result = spi_send_multicommand(flash, cmds);
David Hendricks398714f2014-07-03 17:49:41 -0700294 if (result) {
295 msg_cerr("%s failed during command execution\n", __func__);
David Hendricks43d9afd2015-03-13 20:54:23 -0700296 return -1;
David Hendricks398714f2014-07-03 17:49:41 -0700297 }
298
David Hendricks43d9afd2015-03-13 20:54:23 -0700299 programmer_delay(T_W);
300 return s25f_poll_status(flash);
David Hendricks398714f2014-07-03 17:49:41 -0700301}
302
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700303static int s25fs_restore_cr3nv(struct flashctx *flash, uint8_t cfg)
David Hendricks398714f2014-07-03 17:49:41 -0700304{
305 int ret = 0;
306
307 msg_cdbg("Restoring CR3NV value to 0x%02x\n", cfg);
David Hendricks636c74a2014-12-12 11:30:00 -0800308 ret |= s25fs_write_cr(flash, CR3NV_ADDR, cfg);
David Hendricks398714f2014-07-03 17:49:41 -0700309 ret |= s25fs_software_reset(flash);
310 return ret;
311}
312
David Hendricksa9884852014-12-11 15:31:12 -0800313/* returns state of top/bottom block protection, or <0 to indicate error */
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700314static int s25f_get_tbprot_o(const struct flashctx *flash)
David Hendricksa9884852014-12-11 15:31:12 -0800315{
David Hendricks43d9afd2015-03-13 20:54:23 -0700316 int cr1 = s25f_read_cr1(flash);
David Hendricksa9884852014-12-11 15:31:12 -0800317
David Hendricks43d9afd2015-03-13 20:54:23 -0700318 if (cr1 < 0)
David Hendricksa9884852014-12-11 15:31:12 -0800319 return -1;
320
321 /*
322 * 1 = BP starts at bottom (low address)
323 * 0 = BP start at top (high address)
324 */
David Hendricks43d9afd2015-03-13 20:54:23 -0700325 return cr1 & CR1_TBPROT_O ? 1 : 0;
David Hendricksa9884852014-12-11 15:31:12 -0800326}
327
David Hendricks148a4bf2015-03-13 21:02:42 -0700328/* fills modifier_bits struct, returns 0 to indicate success */
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700329int s25f_get_modifier_bits(const struct flashctx *flash,
Edward O'Callaghan9c4c9a52019-12-04 18:18:01 +1100330 struct modifier_bits *m)
David Hendricks148a4bf2015-03-13 21:02:42 -0700331{
332 int tmp;
333
334 memset(m, 0, sizeof(*m));
335
336 tmp = s25f_get_tbprot_o(flash);
337 if (tmp < 0)
338 return -1;
339 m->tb = tmp;
340
341 return 0;
342}
343
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700344int s25f_set_modifier_bits(const struct flashctx *flash,
Edward O'Callaghan9c4c9a52019-12-04 18:18:01 +1100345 struct modifier_bits *m)
David Hendricks148a4bf2015-03-13 21:02:42 -0700346{
347 int cr1, cr1_orig;
348
349 cr1 = cr1_orig = s25f_read_cr1(flash);
350 if (cr1 < 0)
351 return -1;
352
353 /*
354 * Clear BPNV so that setting BP2-0 in status register gets
355 * written to non-volatile memory.
356 *
357 * For TBPROT:
358 * 1 = BP starts at bottom (low address)
359 * 0 = BP start at top (high address)
360 */
361 cr1 &= ~(CR1_BPNV_O | CR1_TBPROT_O);
362 cr1 |= m->tb ? CR1_TBPROT_O : 0;
363
364 if (cr1 != cr1_orig) {
365 msg_cdbg("%s: setting cr1 bits to 0x%02x\n", __func__, cr1);
366 if (s25f_write_cr1(flash, cr1) < 0)
367 return -1;
368 if (s25f_read_cr1(flash) != cr1) {
369 msg_cerr("%s: failed to set CR1 value\n", __func__);
370 return -1;
371 }
372 } else {
373 msg_cdbg("%s: cr1 bits already match desired value: "
374 "0x%02x\n", __func__, cr1);
375 }
376
377 return 0;
378}
379
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700380int s25fs_block_erase_d8(struct flashctx *flash,
David Hendricks398714f2014-07-03 17:49:41 -0700381 unsigned int addr, unsigned int blocklen)
382{
383 unsigned char cfg;
384 int result;
385 static int cr3nv_checked = 0;
386
387 struct spi_command erase_cmds[] = {
388 {
389 .writecnt = JEDEC_WREN_OUTSIZE,
390 .writearr = (const unsigned char[]){ JEDEC_WREN },
391 .readcnt = 0,
392 .readarr = NULL,
393 }, {
394 .writecnt = JEDEC_BE_D8_OUTSIZE,
395 .writearr = (const unsigned char[]){
396 JEDEC_BE_D8,
397 (addr >> 16) & 0xff,
398 (addr >> 8) & 0xff,
399 (addr & 0xff)
400 },
401 .readcnt = 0,
402 .readarr = NULL,
403 }, {
404 .writecnt = 0,
405 .writearr = NULL,
406 .readcnt = 0,
407 .readarr = NULL,
408 }};
409
410 /* Check if hybrid sector architecture is in use and, if so,
411 * switch to uniform sectors. */
412 if (!cr3nv_checked) {
David Hendricks636c74a2014-12-12 11:30:00 -0800413 cfg = s25fs_read_cr(flash, CR3NV_ADDR);
David Hendricks398714f2014-07-03 17:49:41 -0700414 if (!(cfg & CR3NV_20H_NV)) {
David Hendricks636c74a2014-12-12 11:30:00 -0800415 s25fs_write_cr(flash, CR3NV_ADDR, cfg | CR3NV_20H_NV);
David Hendricks398714f2014-07-03 17:49:41 -0700416 s25fs_software_reset(flash);
417
David Hendricks636c74a2014-12-12 11:30:00 -0800418 cfg = s25fs_read_cr(flash, CR3NV_ADDR);
David Hendricks398714f2014-07-03 17:49:41 -0700419 if (!(cfg & CR3NV_20H_NV)) {
420 msg_cerr("%s: Unable to enable uniform "
421 "block sizes.\n", __func__);
422 return 1;
423 }
424
425 msg_cdbg("\n%s: CR3NV updated (0x%02x -> 0x%02x)\n",
426 __func__, cfg,
David Hendricks636c74a2014-12-12 11:30:00 -0800427 s25fs_read_cr(flash, CR3NV_ADDR));
David Hendricks398714f2014-07-03 17:49:41 -0700428 /* Restore CR3V when flashrom exits */
429 register_chip_restore(s25fs_restore_cr3nv, flash, cfg);
430 }
431
432 cr3nv_checked = 1;
433 }
434
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700435 result = spi_send_multicommand(flash, erase_cmds);
David Hendricks398714f2014-07-03 17:49:41 -0700436 if (result) {
437 msg_cerr("%s failed during command execution at address 0x%x\n",
438 __func__, addr);
439 return result;
440 }
441
David Hendricks43d9afd2015-03-13 20:54:23 -0700442 programmer_delay(S25FS_T_SE);
443 return s25f_poll_status(flash);
David Hendricks398714f2014-07-03 17:49:41 -0700444}
Vadim Bendebury3a501162014-10-21 20:38:13 -0700445
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700446int s25fl_block_erase(struct flashctx *flash,
Vadim Bendebury3a501162014-10-21 20:38:13 -0700447 unsigned int addr, unsigned int blocklen)
448{
Vadim Bendebury3a501162014-10-21 20:38:13 -0700449 int result;
Vadim Bendebury3a501162014-10-21 20:38:13 -0700450
451 struct spi_command erase_cmds[] = {
452 {
453 .writecnt = JEDEC_WREN_OUTSIZE,
454 .writearr = (const unsigned char[]){
455 JEDEC_WREN
456 },
457 .readcnt = 0,
458 .readarr = NULL,
459 }, {
460 .writecnt = JEDEC_BE_DC_OUTSIZE,
461 .writearr = (const unsigned char[]){
462 JEDEC_BE_DC,
463 (addr >> 24) & 0xff,
464 (addr >> 16) & 0xff,
465 (addr >> 8) & 0xff,
466 (addr & 0xff)
467 },
468 .readcnt = 0,
469 .readarr = NULL,
470 }, {
471 .writecnt = 0,
472 .readcnt = 0,
473 }
474 };
475
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700476 result = spi_send_multicommand(flash, erase_cmds);
Vadim Bendebury3a501162014-10-21 20:38:13 -0700477 if (result) {
478 msg_cerr("%s failed during command execution at address 0x%x\n",
479 __func__, addr);
480 return result;
481 }
482
David Hendricks43d9afd2015-03-13 20:54:23 -0700483 programmer_delay(S25FL_T_SE);
484 return s25f_poll_status(flash);
Vadim Bendebury3a501162014-10-21 20:38:13 -0700485}
486
487
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700488int probe_spi_big_spansion(struct flashctx *flash)
Vadim Bendebury3a501162014-10-21 20:38:13 -0700489{
490 static const unsigned char cmd = JEDEC_RDID;
491 int ret;
492 unsigned char dev_id[6]; /* We care only about 6 first bytes */
493
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700494 ret = spi_send_command(flash, sizeof(cmd), sizeof(dev_id), &cmd, dev_id);
Vadim Bendebury3a501162014-10-21 20:38:13 -0700495
496 if (!ret) {
Nikolai Artemiev81e6aa42020-10-08 10:53:42 +1100497 for (size_t i = 0; i < sizeof(dev_id); i++)
Vadim Bendebury3a501162014-10-21 20:38:13 -0700498 msg_gdbg(" 0x%02x", dev_id[i]);
499 msg_gdbg(".\n");
500
Patrick Georgif3fa2992017-02-02 16:24:44 +0100501 if (dev_id[0] == flash->chip->manufacture_id) {
Vadim Bendebury3a501162014-10-21 20:38:13 -0700502 union {
503 uint8_t array[4];
504 uint32_t whole;
505 } model_id;
506
507 /*
508 * The structure of the RDID output is as follows:
509 *
510 * offset value meaning
511 * 00h 01h Manufacturer ID for Spansion
512 * 01h 20h 128 Mb capacity
513 * 01h 02h 256 Mb capacity
514 * 02h 18h 128 Mb capacity
515 * 02h 19h 256 Mb capacity
516 * 03h 4Dh Full size of the RDID output (ignored)
517 * 04h 00h FS: 256-kB physical sectors
518 * 04h 01h FS: 64-kB physical sectors
519 * 04h 00h FL: 256-kB physical sectors
520 * 04h 01h FL: Mix of 64-kB and 4KB overlayed sectors
521 * 05h 80h FL family
522 * 05h 81h FS family
523 *
524 * Need to use bytes 1, 2, 4, and 5 to properly identify one of eight
525 * possible chips:
526 *
527 * 2 types * 2 possible sizes * 2 possible sector layouts
528 *
529 */
530 memcpy(model_id.array, dev_id + 1, 2);
531 memcpy(model_id.array + 2, dev_id + 4, 2);
Patrick Georgif3fa2992017-02-02 16:24:44 +0100532 if (be_to_cpu32(model_id.whole) == flash->chip->model_id)
Vadim Bendebury3a501162014-10-21 20:38:13 -0700533 return 1;
534 }
535 }
536 return 0;
537}