blob: d55c101ed43b448c863eca7c48f9c73d32aabaa3 [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.
33 *
David Hendricks43d9afd2015-03-13 20:54:23 -070034 * s25f.c - Helper functions for Spansion S25FL and S25FS SPI flash chips.
Vadim Bendebury3a501162014-10-21 20:38:13 -070035 * Uses 24 bit addressing for the FS chips and 32 bit addressing for the FL
36 * chips (which is required by the overlayed sector size devices).
37 * TODO: Implement fancy hybrid sector architecture helpers.
David Hendricks398714f2014-07-03 17:49:41 -070038 */
39
Vadim Bendebury3a501162014-10-21 20:38:13 -070040#include <string.h>
41
David Hendricks398714f2014-07-03 17:49:41 -070042#include "chipdrivers.h"
Mayur Panchalf4796862019-08-05 15:46:12 +100043#include "hwaccess.h"
David Hendricks398714f2014-07-03 17:49:41 -070044#include "spi.h"
David Hendricks43d9afd2015-03-13 20:54:23 -070045#include "writeprotect.h"
David Hendricks398714f2014-07-03 17:49:41 -070046
David Hendricks43d9afd2015-03-13 20:54:23 -070047/*
48 * RDAR and WRAR are supported on chips which have more than one set of status
49 * and control registers and take an address of the register to read/write.
50 * WRR, RDSR2, and RDCR are used on chips with a more limited set of control/
51 * status registers.
52 *
53 * WRR is somewhat peculiar. It shares the same opcode as JEDEC_WRSR, and if
54 * given one data byte (following the opcode) it acts the same way. If it's
55 * given two data bytes, the first data byte overwrites status register 1
56 * and the second data byte overwrites config register 1.
57 */
58#define CMD_WRR 0x01
59#define CMD_WRDI 0x04
60#define CMD_RDSR2 0x07 /* note: read SR1 with JEDEC RDSR opcode */
61#define CMD_RDCR 0x35
David Hendricks398714f2014-07-03 17:49:41 -070062#define CMD_RDAR 0x65
63#define CMD_WRAR 0x71
David Hendricks43d9afd2015-03-13 20:54:23 -070064
65/* TODO: For now, commands which use an address assume 24-bit addressing */
66#define CMD_WRR_LEN 3
67#define CMD_WRDI_LEN 1
David Hendricks398714f2014-07-03 17:49:41 -070068#define CMD_RDAR_LEN 4
69#define CMD_WRAR_LEN 5
70
71#define CMD_RSTEN 0x66
72#define CMD_RST 0x99
73
David Hendricksa9884852014-12-11 15:31:12 -080074#define CR1NV_ADDR 0x000002
David Hendricks43d9afd2015-03-13 20:54:23 -070075#define CR1_BPNV_O (1 << 3)
76#define CR1_TBPROT_O (1 << 5)
David Hendricks398714f2014-07-03 17:49:41 -070077#define CR3NV_ADDR 0x000004
78#define CR3NV_20H_NV (1 << 3)
79
David Hendricks43d9afd2015-03-13 20:54:23 -070080/* See "Embedded Algorithm Performance Tables for additional timing specs. */
81#define T_W 145 * 1000 /* NV register write time (145ms) */
82#define T_RPH 35 /* Reset pulse hold time (35us) */
83#define S25FS_T_SE 145 * 1000 /* Sector Erase Time (145ms) */
84#define S25FL_T_SE 130 * 1000 /* Sector Erase Time (130ms) */
85
Souvik Ghoshd75cd672016-06-17 14:21:39 -070086static int s25f_legacy_software_reset(const struct flashctx *flash)
David Hendricks43d9afd2015-03-13 20:54:23 -070087{
88 int result;
89 struct spi_command cmds[] = {
90 {
91 .writecnt = 1,
92 .writearr = (const unsigned char[]){ CMD_RSTEN },
93 .readcnt = 0,
94 .readarr = NULL,
95 }, {
96 .writecnt = 1,
97 .writearr = (const unsigned char[]){ 0xf0 },
98 .readcnt = 0,
99 .readarr = NULL,
100 }, {
101 .writecnt = 0,
102 .writearr = NULL,
103 .readcnt = 0,
104 .readarr = NULL,
105 }};
106
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700107 result = spi_send_multicommand(flash, cmds);
David Hendricks43d9afd2015-03-13 20:54:23 -0700108 if (result) {
109 msg_cerr("%s failed during command execution\n", __func__);
110 return result;
111 }
112
113 /* Allow time for reset command to execute. The datasheet specifies
114 * Trph = 35us, double that to be safe. */
115 programmer_delay(T_RPH * 2);
116
117 return 0;
118}
119
120/* "Legacy software reset" is disabled by default on S25FS, use this instead. */
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700121static int s25fs_software_reset(struct flashctx *flash)
David Hendricks43d9afd2015-03-13 20:54:23 -0700122{
123 int result;
124 struct spi_command cmds[] = {
125 {
126 .writecnt = 1,
127 .writearr = (const unsigned char[]){ CMD_RSTEN },
128 .readcnt = 0,
129 .readarr = NULL,
130 }, {
131 .writecnt = 1,
132 .writearr = (const unsigned char[]){ CMD_RST },
133 .readcnt = 0,
134 .readarr = NULL,
135 }, {
136 .writecnt = 0,
137 .writearr = NULL,
138 .readcnt = 0,
139 .readarr = NULL,
140 }};
141
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700142 result = spi_send_multicommand(flash, cmds);
David Hendricks43d9afd2015-03-13 20:54:23 -0700143 if (result) {
144 msg_cerr("%s failed during command execution\n", __func__);
145 return result;
146 }
147
148 /* Allow time for reset command to execute. Double tRPH to be safe. */
149 programmer_delay(T_RPH * 2);
150
151 return 0;
152}
153
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700154static int s25f_poll_status(const struct flashctx *flash)
David Hendricks43d9afd2015-03-13 20:54:23 -0700155{
Ramya Vijaykumar4af3f822016-01-27 11:51:27 +0530156 uint8_t tmp = spi_read_status_register(flash);
David Hendricks43d9afd2015-03-13 20:54:23 -0700157
Edward O'Callaghan8b5e4732019-03-05 15:27:53 +1100158 while (tmp & SPI_SR_WIP) {
David Hendricks43d9afd2015-03-13 20:54:23 -0700159 /*
160 * The WIP bit on S25F chips remains set to 1 if erase or
161 * programming errors occur, so we must check for those
162 * errors here. If an error is encountered, do a software
163 * reset to clear WIP and other volatile bits, otherwise
164 * the chip will be unresponsive to further commands.
165 */
Edward O'Callaghan1945f1e2019-03-18 13:12:51 +1100166 if (tmp & SPI_SR_ERA_ERR) {
David Hendricks43d9afd2015-03-13 20:54:23 -0700167 msg_cerr("Erase error occurred\n");
168 s25f_legacy_software_reset(flash);
169 return -1;
170 }
171
172 if (tmp & (1 << 6)) {
173 msg_cerr("Programming error occurred\n");
174 s25f_legacy_software_reset(flash);
175 return -1;
176 }
177
178 programmer_delay(1000 * 10);
Ramya Vijaykumar4af3f822016-01-27 11:51:27 +0530179 tmp = spi_read_status_register(flash);
David Hendricks43d9afd2015-03-13 20:54:23 -0700180 }
181
182 return 0;
183}
184
185/* "Read Any Register" instruction only supported on S25FS */
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700186static int s25fs_read_cr(const struct flashctx *flash, uint32_t addr)
David Hendricks398714f2014-07-03 17:49:41 -0700187{
188 int result;
189 uint8_t cfg;
190 /* By default, 8 dummy cycles are necessary for variable-latency
191 commands such as RDAR (see CR2NV[3:0]). */
192 unsigned char read_cr_cmd[] = {
193 CMD_RDAR,
194 (addr >> 16) & 0xff,
195 (addr >> 8) & 0xff,
196 (addr & 0xff),
197 0x00, 0x00, 0x00, 0x00,
198 0x00, 0x00, 0x00, 0x00,
199 };
200
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700201 result = spi_send_command(flash, sizeof(read_cr_cmd), 1, read_cr_cmd, &cfg);
David Hendricks398714f2014-07-03 17:49:41 -0700202 if (result) {
203 msg_cerr("%s failed during command execution at address 0x%x\n",
204 __func__, addr);
David Hendricks688b5e22014-12-12 11:15:44 -0800205 return -1;
David Hendricks398714f2014-07-03 17:49:41 -0700206 }
207
208 return cfg;
209}
210
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700211static int s25f_read_cr1(const struct flashctx *flash)
David Hendricks43d9afd2015-03-13 20:54:23 -0700212{
213 int result;
214 uint8_t cfg;
215 unsigned char read_cr_cmd[] = { CMD_RDCR };
216
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700217 result = spi_send_command(flash, sizeof(read_cr_cmd), 1, read_cr_cmd, &cfg);
David Hendricks43d9afd2015-03-13 20:54:23 -0700218 if (result) {
219 msg_cerr("%s failed during command execution\n", __func__);
220 return -1;
221 }
222
223 return cfg;
224}
225
226/* "Write Any Register" instruction only supported on S25FS */
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700227static int s25fs_write_cr(const struct flashctx *flash,
David Hendricks43d9afd2015-03-13 20:54:23 -0700228 uint32_t addr, uint8_t data)
David Hendricks398714f2014-07-03 17:49:41 -0700229{
230 int result;
231 struct spi_command cmds[] = {
232 {
233 .writecnt = JEDEC_WREN_OUTSIZE,
234 .writearr = (const unsigned char[]){ JEDEC_WREN },
235 .readcnt = 0,
236 .readarr = NULL,
237 }, {
238 .writecnt = CMD_WRAR_LEN,
239 .writearr = (const unsigned char[]){
240 CMD_WRAR,
241 (addr >> 16) & 0xff,
242 (addr >> 8) & 0xff,
243 (addr & 0xff),
244 data
245 },
246 .readcnt = 0,
247 .readarr = NULL,
248 }, {
249 .writecnt = 0,
250 .writearr = NULL,
251 .readcnt = 0,
252 .readarr = NULL,
253 }};
254
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700255 result = spi_send_multicommand(flash, cmds);
David Hendricks398714f2014-07-03 17:49:41 -0700256 if (result) {
257 msg_cerr("%s failed during command execution at address 0x%x\n",
258 __func__, addr);
David Hendricks688b5e22014-12-12 11:15:44 -0800259 return -1;
David Hendricks398714f2014-07-03 17:49:41 -0700260 }
261
David Hendricks43d9afd2015-03-13 20:54:23 -0700262 programmer_delay(T_W);
263 return s25f_poll_status(flash);
David Hendricks398714f2014-07-03 17:49:41 -0700264}
265
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700266static int s25f_write_cr1(const struct flashctx *flash, uint8_t data)
David Hendricks398714f2014-07-03 17:49:41 -0700267{
268 int result;
269 struct spi_command cmds[] = {
270 {
David Hendricks43d9afd2015-03-13 20:54:23 -0700271 .writecnt = JEDEC_WREN_OUTSIZE,
272 .writearr = (const unsigned char[]){ JEDEC_WREN },
David Hendricks398714f2014-07-03 17:49:41 -0700273 .readcnt = 0,
274 .readarr = NULL,
275 }, {
David Hendricks43d9afd2015-03-13 20:54:23 -0700276 .writecnt = CMD_WRR_LEN,
277 .writearr = (const unsigned char[]){
278 CMD_WRR,
Ramya Vijaykumar4af3f822016-01-27 11:51:27 +0530279 spi_read_status_register(flash),
David Hendricks43d9afd2015-03-13 20:54:23 -0700280 data,
281 },
David Hendricks398714f2014-07-03 17:49:41 -0700282 .readcnt = 0,
283 .readarr = NULL,
284 }, {
285 .writecnt = 0,
286 .writearr = NULL,
287 .readcnt = 0,
288 .readarr = NULL,
289 }};
290
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700291 result = spi_send_multicommand(flash, cmds);
David Hendricks398714f2014-07-03 17:49:41 -0700292 if (result) {
293 msg_cerr("%s failed during command execution\n", __func__);
David Hendricks43d9afd2015-03-13 20:54:23 -0700294 return -1;
David Hendricks398714f2014-07-03 17:49:41 -0700295 }
296
David Hendricks43d9afd2015-03-13 20:54:23 -0700297 programmer_delay(T_W);
298 return s25f_poll_status(flash);
David Hendricks398714f2014-07-03 17:49:41 -0700299}
300
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700301static int s25fs_restore_cr3nv(struct flashctx *flash, uint8_t cfg)
David Hendricks398714f2014-07-03 17:49:41 -0700302{
303 int ret = 0;
304
305 msg_cdbg("Restoring CR3NV value to 0x%02x\n", cfg);
David Hendricks636c74a2014-12-12 11:30:00 -0800306 ret |= s25fs_write_cr(flash, CR3NV_ADDR, cfg);
David Hendricks398714f2014-07-03 17:49:41 -0700307 ret |= s25fs_software_reset(flash);
308 return ret;
309}
310
David Hendricksa9884852014-12-11 15:31:12 -0800311/* returns state of top/bottom block protection, or <0 to indicate error */
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700312static int s25f_get_tbprot_o(const struct flashctx *flash)
David Hendricksa9884852014-12-11 15:31:12 -0800313{
David Hendricks43d9afd2015-03-13 20:54:23 -0700314 int cr1 = s25f_read_cr1(flash);
David Hendricksa9884852014-12-11 15:31:12 -0800315
David Hendricks43d9afd2015-03-13 20:54:23 -0700316 if (cr1 < 0)
David Hendricksa9884852014-12-11 15:31:12 -0800317 return -1;
318
319 /*
320 * 1 = BP starts at bottom (low address)
321 * 0 = BP start at top (high address)
322 */
David Hendricks43d9afd2015-03-13 20:54:23 -0700323 return cr1 & CR1_TBPROT_O ? 1 : 0;
David Hendricksa9884852014-12-11 15:31:12 -0800324}
325
David Hendricks148a4bf2015-03-13 21:02:42 -0700326/* fills modifier_bits struct, returns 0 to indicate success */
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700327int s25f_get_modifier_bits(const struct flashctx *flash,
Edward O'Callaghan9c4c9a52019-12-04 18:18:01 +1100328 struct modifier_bits *m)
David Hendricks148a4bf2015-03-13 21:02:42 -0700329{
330 int tmp;
331
332 memset(m, 0, sizeof(*m));
333
334 tmp = s25f_get_tbprot_o(flash);
335 if (tmp < 0)
336 return -1;
337 m->tb = tmp;
338
339 return 0;
340}
341
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700342int s25f_set_modifier_bits(const struct flashctx *flash,
Edward O'Callaghan9c4c9a52019-12-04 18:18:01 +1100343 struct modifier_bits *m)
David Hendricks148a4bf2015-03-13 21:02:42 -0700344{
345 int cr1, cr1_orig;
346
347 cr1 = cr1_orig = s25f_read_cr1(flash);
348 if (cr1 < 0)
349 return -1;
350
351 /*
352 * Clear BPNV so that setting BP2-0 in status register gets
353 * written to non-volatile memory.
354 *
355 * For TBPROT:
356 * 1 = BP starts at bottom (low address)
357 * 0 = BP start at top (high address)
358 */
359 cr1 &= ~(CR1_BPNV_O | CR1_TBPROT_O);
360 cr1 |= m->tb ? CR1_TBPROT_O : 0;
361
362 if (cr1 != cr1_orig) {
363 msg_cdbg("%s: setting cr1 bits to 0x%02x\n", __func__, cr1);
364 if (s25f_write_cr1(flash, cr1) < 0)
365 return -1;
366 if (s25f_read_cr1(flash) != cr1) {
367 msg_cerr("%s: failed to set CR1 value\n", __func__);
368 return -1;
369 }
370 } else {
371 msg_cdbg("%s: cr1 bits already match desired value: "
372 "0x%02x\n", __func__, cr1);
373 }
374
375 return 0;
376}
377
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700378int s25fs_block_erase_d8(struct flashctx *flash,
David Hendricks398714f2014-07-03 17:49:41 -0700379 unsigned int addr, unsigned int blocklen)
380{
381 unsigned char cfg;
382 int result;
383 static int cr3nv_checked = 0;
384
385 struct spi_command erase_cmds[] = {
386 {
387 .writecnt = JEDEC_WREN_OUTSIZE,
388 .writearr = (const unsigned char[]){ JEDEC_WREN },
389 .readcnt = 0,
390 .readarr = NULL,
391 }, {
392 .writecnt = JEDEC_BE_D8_OUTSIZE,
393 .writearr = (const unsigned char[]){
394 JEDEC_BE_D8,
395 (addr >> 16) & 0xff,
396 (addr >> 8) & 0xff,
397 (addr & 0xff)
398 },
399 .readcnt = 0,
400 .readarr = NULL,
401 }, {
402 .writecnt = 0,
403 .writearr = NULL,
404 .readcnt = 0,
405 .readarr = NULL,
406 }};
407
408 /* Check if hybrid sector architecture is in use and, if so,
409 * switch to uniform sectors. */
410 if (!cr3nv_checked) {
David Hendricks636c74a2014-12-12 11:30:00 -0800411 cfg = s25fs_read_cr(flash, CR3NV_ADDR);
David Hendricks398714f2014-07-03 17:49:41 -0700412 if (!(cfg & CR3NV_20H_NV)) {
David Hendricks636c74a2014-12-12 11:30:00 -0800413 s25fs_write_cr(flash, CR3NV_ADDR, cfg | CR3NV_20H_NV);
David Hendricks398714f2014-07-03 17:49:41 -0700414 s25fs_software_reset(flash);
415
David Hendricks636c74a2014-12-12 11:30:00 -0800416 cfg = s25fs_read_cr(flash, CR3NV_ADDR);
David Hendricks398714f2014-07-03 17:49:41 -0700417 if (!(cfg & CR3NV_20H_NV)) {
418 msg_cerr("%s: Unable to enable uniform "
419 "block sizes.\n", __func__);
420 return 1;
421 }
422
423 msg_cdbg("\n%s: CR3NV updated (0x%02x -> 0x%02x)\n",
424 __func__, cfg,
David Hendricks636c74a2014-12-12 11:30:00 -0800425 s25fs_read_cr(flash, CR3NV_ADDR));
David Hendricks398714f2014-07-03 17:49:41 -0700426 /* Restore CR3V when flashrom exits */
427 register_chip_restore(s25fs_restore_cr3nv, flash, cfg);
428 }
429
430 cr3nv_checked = 1;
431 }
432
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700433 result = spi_send_multicommand(flash, erase_cmds);
David Hendricks398714f2014-07-03 17:49:41 -0700434 if (result) {
435 msg_cerr("%s failed during command execution at address 0x%x\n",
436 __func__, addr);
437 return result;
438 }
439
David Hendricks43d9afd2015-03-13 20:54:23 -0700440 programmer_delay(S25FS_T_SE);
441 return s25f_poll_status(flash);
David Hendricks398714f2014-07-03 17:49:41 -0700442}
Vadim Bendebury3a501162014-10-21 20:38:13 -0700443
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700444int s25fl_block_erase(struct flashctx *flash,
Vadim Bendebury3a501162014-10-21 20:38:13 -0700445 unsigned int addr, unsigned int blocklen)
446{
Vadim Bendebury3a501162014-10-21 20:38:13 -0700447 int result;
Vadim Bendebury3a501162014-10-21 20:38:13 -0700448
449 struct spi_command erase_cmds[] = {
450 {
451 .writecnt = JEDEC_WREN_OUTSIZE,
452 .writearr = (const unsigned char[]){
453 JEDEC_WREN
454 },
455 .readcnt = 0,
456 .readarr = NULL,
457 }, {
458 .writecnt = JEDEC_BE_DC_OUTSIZE,
459 .writearr = (const unsigned char[]){
460 JEDEC_BE_DC,
461 (addr >> 24) & 0xff,
462 (addr >> 16) & 0xff,
463 (addr >> 8) & 0xff,
464 (addr & 0xff)
465 },
466 .readcnt = 0,
467 .readarr = NULL,
468 }, {
469 .writecnt = 0,
470 .readcnt = 0,
471 }
472 };
473
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700474 result = spi_send_multicommand(flash, erase_cmds);
Vadim Bendebury3a501162014-10-21 20:38:13 -0700475 if (result) {
476 msg_cerr("%s failed during command execution at address 0x%x\n",
477 __func__, addr);
478 return result;
479 }
480
David Hendricks43d9afd2015-03-13 20:54:23 -0700481 programmer_delay(S25FL_T_SE);
482 return s25f_poll_status(flash);
Vadim Bendebury3a501162014-10-21 20:38:13 -0700483}
484
485
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700486int probe_spi_big_spansion(struct flashctx *flash)
Vadim Bendebury3a501162014-10-21 20:38:13 -0700487{
488 static const unsigned char cmd = JEDEC_RDID;
489 int ret;
490 unsigned char dev_id[6]; /* We care only about 6 first bytes */
491
Souvik Ghoshd75cd672016-06-17 14:21:39 -0700492 ret = spi_send_command(flash, sizeof(cmd), sizeof(dev_id), &cmd, dev_id);
Vadim Bendebury3a501162014-10-21 20:38:13 -0700493
494 if (!ret) {
495 int i;
496
497 for (i = 0; i < sizeof(dev_id); i++)
498 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}