1 /***************************************************************************
2 * Copyright (C) 2007 by Dominic Rath *
3 * Dominic.Rath@gmx.de *
4 * Copyright (C) 2009 Michael Schwingen *
5 * michael@schwingen.org *
7 * This program is free software; you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation; either version 2 of the License, or *
10 * (at your option) any later version. *
12 * This program is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
17 * You should have received a copy of the GNU General Public License *
18 * along with this program; if not, write to the *
19 * Free Software Foundation, Inc., *
20 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
21 ***************************************************************************/
32 #define MB (1024*1024)
33 #define ERASE_REGION(num, size) (((size/256) << 16) | (num-1))
35 /* non-CFI compatible flashes */
36 static struct non_cfi non_cfi_flashes[] = {
42 .interface_desc = 0x0, /* x8 only device */
43 .max_buf_write_size = 0x0,
44 .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
45 .num_erase_regions = 1,
48 ERASE_REGION(16, 4*KB)
56 .interface_desc = 0x0, /* x8 only device */
57 .max_buf_write_size = 0x0,
58 .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
59 .num_erase_regions = 1,
62 ERASE_REGION(32, 4*KB)
70 .interface_desc = 0x0, /* x8 only device */
71 .max_buf_write_size = 0x0,
72 .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
73 .num_erase_regions = 1,
76 ERASE_REGION(64, 4*KB)
84 .interface_desc = 0x0, /* x8 only device */
85 .max_buf_write_size = 0x0,
86 .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
87 .num_erase_regions = 1,
90 ERASE_REGION(128, 4*KB)
94 .mfr = CFI_MFR_AMD, /* Spansion AM29LV040B */
98 .interface_desc = 0x0, /* x8 only device */
99 .max_buf_write_size = 0x0,
100 .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
101 .num_erase_regions = 1,
104 ERASE_REGION(8, 64*KB)
112 .interface_desc = 0x2, /* x8 or x16 device */
113 .max_buf_write_size = 0x0,
114 .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
115 .num_erase_regions = 1,
118 ERASE_REGION(128, 4*KB)
123 .id = 0xd6, /* ST29F400BB */
126 .interface_desc = 0x2, /* x8 or x16 device with nBYTE */
127 .max_buf_write_size = 0x0,
128 .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
129 .num_erase_regions = 4,
132 ERASE_REGION(1, 16*KB),
133 ERASE_REGION(2, 8*KB),
134 ERASE_REGION(1, 32*KB),
135 ERASE_REGION(7, 64*KB)
140 .id = 0xd5, /* ST29F400BT */
143 .interface_desc = 0x2, /* x8 or x16 device with nBYTE */
144 .max_buf_write_size = 0x0,
145 .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
146 .num_erase_regions = 4,
149 ERASE_REGION(7, 64*KB),
150 ERASE_REGION(1, 32*KB),
151 ERASE_REGION(2, 8*KB),
152 ERASE_REGION(1, 16*KB)
156 /* SST 39VF* do not support DQ5 status polling - this currently is
157 only supported by the host algorithm, not by the target code using
159 Only true for 8-bit and 32-bit wide memories. 16-bit wide memories
160 without DQ5 status polling are supported by the target code.
164 .id = 0x2782, /* SST39xF160 */
167 .interface_desc = 0x2, /* x8 or x16 device with nBYTE */
168 .max_buf_write_size = 0x0,
169 .status_poll_mask = CFI_STATUS_POLL_MASK_DQ6_DQ7,
170 .num_erase_regions = 1,
173 ERASE_REGION(512, 4*KB)
178 .id = 0x2783, /* SST39VF320 */
181 .interface_desc = 0x2, /* x8 or x16 device with nBYTE */
182 .max_buf_write_size = 0x0,
183 .status_poll_mask = CFI_STATUS_POLL_MASK_DQ6_DQ7,
184 .num_erase_regions = 1,
187 ERASE_REGION(1024, 4*KB)
192 .id = 0x234b, /* SST39VF1601 */
195 .interface_desc = 0x2, /* x8 or x16 device with nBYTE */
196 .max_buf_write_size = 0x0,
197 .status_poll_mask = CFI_STATUS_POLL_MASK_DQ6_DQ7,
198 .num_erase_regions = 1,
201 ERASE_REGION(512, 4*KB)
206 .id = 0x274b, /* SST39WF1601 */
209 .interface_desc = 0x2, /* x8 or x16 device with nBYTE */
210 .max_buf_write_size = 0x0,
211 .status_poll_mask = CFI_STATUS_POLL_MASK_DQ6_DQ7,
212 .num_erase_regions = 1,
215 ERASE_REGION(512, 4*KB)
220 .id = 0x234a, /* SST39VF1602 */
223 .interface_desc = 0x2, /* x8 or x16 device with nBYTE */
224 .max_buf_write_size = 0x0,
225 .status_poll_mask = CFI_STATUS_POLL_MASK_DQ6_DQ7,
226 .num_erase_regions = 1,
229 ERASE_REGION(512, 4*KB)
234 .id = 0x235b, /* SST39VF3201 */
237 .interface_desc = 0x2, /* x8 or x16 device with nBYTE */
238 .max_buf_write_size = 0x0,
239 .status_poll_mask = CFI_STATUS_POLL_MASK_DQ6_DQ7,
240 .num_erase_regions = 1,
243 ERASE_REGION(1024, 4*KB)
248 .id = 0x235a, /* SST39VF3202 */
251 .interface_desc = 0x2, /* x8 or x16 device with nBYTE */
252 .max_buf_write_size = 0x0,
253 .status_poll_mask = CFI_STATUS_POLL_MASK_DQ6_DQ7,
254 .num_erase_regions = 1,
257 ERASE_REGION(1024, 4*KB)
262 .id = 0x236d, /* SST39VF6401B */
265 .interface_desc = 0x2, /* x8 or x16 device with nBYTE */
266 .max_buf_write_size = 0x0,
267 .status_poll_mask = CFI_STATUS_POLL_MASK_DQ6_DQ7,
268 .num_erase_regions = 1,
271 ERASE_REGION(2048, 4*KB)
276 .id = 0x22ab, /* AM29F400BB */
279 .interface_desc = 0x2, /* x8 or x16 device with nBYTE */
280 .max_buf_write_size = 0x0,
281 .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
282 .num_erase_regions = 4,
285 ERASE_REGION(1, 16*KB),
286 ERASE_REGION(2, 8*KB),
287 ERASE_REGION(1, 32*KB),
288 ERASE_REGION(7, 64*KB)
293 .id = 0x2223, /* AM29F400BT */
296 .interface_desc = 0x2, /* x8 or x16 device with nBYTE */
297 .max_buf_write_size = 0x0,
298 .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
299 .num_erase_regions = 4,
302 ERASE_REGION(7, 64*KB),
303 ERASE_REGION(1, 32*KB),
304 ERASE_REGION(2, 8*KB),
305 ERASE_REGION(1, 16*KB)
309 .mfr = CFI_MFR_FUJITSU,
310 .id = 0x226b, /* AM29SL800DB */
313 .interface_desc = 0x2, /* x8 or x16 device with nBYTE */
314 .max_buf_write_size = 0x0,
315 .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
316 .num_erase_regions = 4,
319 ERASE_REGION(1, 16*KB),
320 ERASE_REGION(2, 8*KB),
321 ERASE_REGION(1, 32*KB),
322 ERASE_REGION(15, 64*KB)
326 .mfr = CFI_MFR_FUJITSU,
327 .id = 0x22ea, /* MBM29SL800TE */
330 .interface_desc = 0x2, /* x8 or x16 device with nBYTE */
331 .max_buf_write_size = 0x0,
332 .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
333 .num_erase_regions = 4,
336 ERASE_REGION(15, 64*KB),
337 ERASE_REGION(1, 32*KB),
338 ERASE_REGION(2, 8*KB),
339 ERASE_REGION(1, 16*KB)
343 .mfr = CFI_MFR_FUJITSU,
344 .id = 0xba, /* 29LV400BC */
347 .interface_desc = 0x1, /* x8 or x16 device w/ nBYTE */
348 .max_buf_write_size = 0x00,
349 .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
350 .num_erase_regions = 4,
353 ERASE_REGION(1, 16*KB),
354 ERASE_REGION(2, 8*KB),
355 ERASE_REGION(1, 32*KB),
356 ERASE_REGION(7, 64*KB)
361 .id = 0xb31a, /* A29L800A */
364 .interface_desc = 0x2,
365 .max_buf_write_size = 0x0,
366 .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
367 .num_erase_regions = 4,
370 ERASE_REGION(1, 16*KB),
371 ERASE_REGION(2, 8*KB),
372 ERASE_REGION(1, 32*KB),
373 ERASE_REGION(15, 64*KB)
378 .id = 0x225b, /* MX29LV800B */
381 .interface_desc = 0x2, /* x8 or x16 device with nBYTE */
382 .max_buf_write_size = 0x0,
383 .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
384 .num_erase_regions = 4,
387 ERASE_REGION(1, 16*KB),
388 ERASE_REGION(2, 8*KB),
389 ERASE_REGION(1, 32*KB),
390 ERASE_REGION(15, 64*KB)
396 .id = 0x2249, /* MX29LV160AB: 2MB */
399 .interface_desc = 0x2, /* x8 or x16 device with nBYTE */
400 .max_buf_write_size = 0x0,
401 .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
402 .num_erase_regions = 4,
405 ERASE_REGION(1, 16*KB),
406 ERASE_REGION(2, 8*KB),
407 ERASE_REGION(1, 32*KB),
408 ERASE_REGION(31, 64*KB)
413 .id = 0x22C4, /* MX29LV160AT: 2MB */
416 .interface_desc = 0x2, /* x8 or x16 device with nBYTE */
417 .max_buf_write_size = 0x0,
418 .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
419 .num_erase_regions = 4,
422 ERASE_REGION(31, 64*KB),
423 ERASE_REGION(1, 32*KB),
424 ERASE_REGION(2, 8*KB),
425 ERASE_REGION(1, 16*KB)
430 .id = 0x225b, /* EN29LV800BB */
433 .interface_desc = 0x2, /* x8 or x16 device with nBYTE */
434 .max_buf_write_size = 0x0,
435 .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
436 .num_erase_regions = 4,
439 ERASE_REGION(1, 16*KB),
440 ERASE_REGION(2, 8*KB),
441 ERASE_REGION(1, 32*KB),
442 ERASE_REGION(15, 64*KB)
446 .mfr = CFI_MFR_ATMEL,
447 .id = 0x00c0, /* Atmel 49BV1614 */
450 .interface_desc = 0x2, /* x8 or x16 device with nBYTE */
451 .max_buf_write_size = 0x0,
452 .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
453 .num_erase_regions = 3,
456 ERASE_REGION(8, 8*KB),
457 ERASE_REGION(2, 32*KB),
458 ERASE_REGION(30, 64*KB)
462 .mfr = CFI_MFR_ATMEL,
463 .id = 0xC2, /* Atmel 49BV1614T */
466 .interface_desc = 0x2, /* x8 or x16 device with nBYTE */
467 .max_buf_write_size = 0x0,
468 .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
469 .num_erase_regions = 3,
472 ERASE_REGION(30, 64*KB),
473 ERASE_REGION(2, 32*KB),
474 ERASE_REGION(8, 8*KB)
479 .id = 0x225b, /* S29AL008D */
482 .interface_desc = 0x2, /* x8 or x16 device with nBYTE */
483 .max_buf_write_size = 0x0,
484 .status_poll_mask = CFI_STATUS_POLL_MASK_DQ5_DQ6_DQ7,
485 .num_erase_regions = 4,
488 ERASE_REGION(1, 16*KB),
489 ERASE_REGION(2, 8*KB),
490 ERASE_REGION(1, 32*KB),
491 ERASE_REGION(15, 64*KB)
500 void cfi_fixup_non_cfi(struct flash_bank *bank)
503 struct cfi_flash_bank *cfi_info = bank->driver_priv;
504 struct non_cfi *non_cfi = non_cfi_flashes;
506 if(cfi_info->x16_as_x8)
511 for (non_cfi = non_cfi_flashes; non_cfi->mfr; non_cfi++)
513 if ((cfi_info->manufacturer == non_cfi->mfr)
514 && (cfi_info->device_id == (non_cfi->id & mask)))
520 /* only fixup jedec flashs found in table */
524 cfi_info->not_cfi = 1;
526 /* fill in defaults for non-critical data */
527 cfi_info->vcc_min = 0x0;
528 cfi_info->vcc_max = 0x0;
529 cfi_info->vpp_min = 0x0;
530 cfi_info->vpp_max = 0x0;
531 /* these are used for timeouts - use vales that should be long enough
532 for normal operation. */
533 cfi_info->word_write_timeout_typ = 0x0a;
534 cfi_info->buf_write_timeout_typ = 0x0d;
535 cfi_info->block_erase_timeout_typ = 0x0d;
536 cfi_info->chip_erase_timeout_typ = 0x10;
537 cfi_info->word_write_timeout_max = 0x0;
538 cfi_info->buf_write_timeout_max = 0x0;
539 cfi_info->block_erase_timeout_max = 0x0;
540 cfi_info->chip_erase_timeout_max = 0x0;
542 cfi_info->qry[0] = 'Q';
543 cfi_info->qry[1] = 'R';
544 cfi_info->qry[2] = 'Y';
546 cfi_info->pri_id = non_cfi->pri_id;
547 cfi_info->pri_addr = 0x0;
548 cfi_info->alt_id = 0x0;
549 cfi_info->alt_addr = 0x0;
550 cfi_info->alt_ext = NULL;
552 cfi_info->interface_desc = non_cfi->interface_desc;
553 cfi_info->max_buf_write_size = non_cfi->max_buf_write_size;
554 cfi_info->status_poll_mask = non_cfi->status_poll_mask;
555 cfi_info->num_erase_regions = non_cfi->num_erase_regions;
556 size_t erase_region_info_size = sizeof(*cfi_info->erase_region_info) *
557 cfi_info->num_erase_regions;
558 cfi_info->erase_region_info = malloc(erase_region_info_size);
559 memcpy(cfi_info->erase_region_info,
560 non_cfi->erase_region_info, erase_region_info_size);
561 cfi_info->dev_size = non_cfi->dev_size;
563 if (cfi_info->pri_id == 0x2)
565 struct cfi_spansion_pri_ext *pri_ext = malloc(sizeof(struct cfi_spansion_pri_ext));
567 pri_ext->pri[0] = 'P';
568 pri_ext->pri[1] = 'R';
569 pri_ext->pri[2] = 'I';
571 pri_ext->major_version = '1';
572 pri_ext->minor_version = '0';
574 pri_ext->SiliconRevision = 0x0;
575 pri_ext->EraseSuspend = 0x0;
576 pri_ext->EraseSuspend = 0x0;
577 pri_ext->BlkProt = 0x0;
578 pri_ext->TmpBlkUnprotect = 0x0;
579 pri_ext->BlkProtUnprot = 0x0;
580 pri_ext->SimultaneousOps = 0x0;
581 pri_ext->BurstMode = 0x0;
582 pri_ext->PageMode = 0x0;
583 pri_ext->VppMin = 0x0;
584 pri_ext->VppMax = 0x0;
585 pri_ext->TopBottom = 0x0;
587 pri_ext->_unlock1 = 0x5555;
588 pri_ext->_unlock2 = 0x2AAA;
589 pri_ext->_reversed_geometry = 0;
591 cfi_info->pri_ext = pri_ext;
592 } else if ((cfi_info->pri_id == 0x1) || (cfi_info->pri_id == 0x3))
594 LOG_ERROR("BUG: non-CFI flashes using the Intel commandset are not yet supported");