|
|
1.1 root 1: /*
2: * CFI parallel flash with AMD command set emulation
1.1.1.3 root 3: *
1.1 root 4: * Copyright (c) 2005 Jocelyn Mayer
5: *
6: * This library is free software; you can redistribute it and/or
7: * modify it under the terms of the GNU Lesser General Public
8: * License as published by the Free Software Foundation; either
9: * version 2 of the License, or (at your option) any later version.
10: *
11: * This library is distributed in the hope that it will be useful,
12: * but WITHOUT ANY WARRANTY; without even the implied warranty of
13: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14: * Lesser General Public License for more details.
15: *
16: * You should have received a copy of the GNU Lesser General Public
1.1.1.5 root 17: * License along with this library; if not, see <http://www.gnu.org/licenses/>.
1.1 root 18: */
19:
20: /*
21: * For now, this code can emulate flashes of 1, 2 or 4 bytes width.
22: * Supported commands/modes are:
23: * - flash read
24: * - flash write
25: * - flash ID read
26: * - sector erase
27: * - chip erase
28: * - unlock bypass command
29: * - CFI queries
30: *
31: * It does not support flash interleaving.
32: * It does not implement boot blocs with reduced size
33: * It does not implement software data protection as found in many real chips
34: * It does not implement erase suspend/resume commands
35: * It does not implement multiple sectors erase
36: */
37:
1.1.1.3 root 38: #include "hw.h"
39: #include "flash.h"
40: #include "qemu-timer.h"
41: #include "block.h"
1.1 root 42:
43: //#define PFLASH_DEBUG
44: #ifdef PFLASH_DEBUG
1.1.1.5 root 45: #define DPRINTF(fmt, ...) \
1.1 root 46: do { \
1.1.1.5 root 47: printf("PFLASH: " fmt , ## __VA_ARGS__); \
1.1 root 48: } while (0)
49: #else
1.1.1.5 root 50: #define DPRINTF(fmt, ...) do { } while (0)
1.1 root 51: #endif
52:
53: struct pflash_t {
54: BlockDriverState *bs;
1.1.1.3 root 55: target_phys_addr_t base;
56: uint32_t sector_len;
1.1.1.4 root 57: uint32_t chip_len;
58: int mappings;
1.1 root 59: int width;
60: int wcycle; /* if 0, the flash is read normally */
61: int bypass;
62: int ro;
63: uint8_t cmd;
64: uint8_t status;
65: uint16_t ident[4];
1.1.1.4 root 66: uint16_t unlock_addr[2];
1.1 root 67: uint8_t cfi_len;
68: uint8_t cfi_table[0x52];
69: QEMUTimer *timer;
70: ram_addr_t off;
71: int fl_mem;
1.1.1.4 root 72: int rom_mode;
1.1 root 73: void *storage;
74: };
75:
1.1.1.4 root 76: static void pflash_register_memory(pflash_t *pfl, int rom_mode)
77: {
78: unsigned long phys_offset = pfl->fl_mem;
79: int i;
80:
81: if (rom_mode)
82: phys_offset |= pfl->off | IO_MEM_ROMD;
83: pfl->rom_mode = rom_mode;
84:
85: for (i = 0; i < pfl->mappings; i++)
86: cpu_register_physical_memory(pfl->base + i * pfl->chip_len,
87: pfl->chip_len, phys_offset);
88: }
89:
1.1 root 90: static void pflash_timer (void *opaque)
91: {
92: pflash_t *pfl = opaque;
93:
94: DPRINTF("%s: command %02x done\n", __func__, pfl->cmd);
95: /* Reset flash */
96: pfl->status ^= 0x80;
97: if (pfl->bypass) {
98: pfl->wcycle = 2;
99: } else {
1.1.1.4 root 100: pflash_register_memory(pfl, 1);
1.1 root 101: pfl->wcycle = 0;
102: }
103: pfl->cmd = 0;
104: }
105:
1.1.1.7 root 106: static uint32_t pflash_read (pflash_t *pfl, target_phys_addr_t offset,
107: int width, int be)
1.1 root 108: {
1.1.1.7 root 109: target_phys_addr_t boff;
1.1 root 110: uint32_t ret;
111: uint8_t *p;
112:
1.1.1.7 root 113: DPRINTF("%s: offset " TARGET_FMT_plx "\n", __func__, offset);
1.1 root 114: ret = -1;
1.1.1.4 root 115: if (pfl->rom_mode) {
116: /* Lazy reset of to ROMD mode */
117: if (pfl->wcycle == 0)
118: pflash_register_memory(pfl, 1);
119: }
120: offset &= pfl->chip_len - 1;
1.1 root 121: boff = offset & 0xFF;
122: if (pfl->width == 2)
123: boff = boff >> 1;
124: else if (pfl->width == 4)
125: boff = boff >> 2;
126: switch (pfl->cmd) {
127: default:
128: /* This should never happen : reset state & treat it as a read*/
129: DPRINTF("%s: unknown command state: %x\n", __func__, pfl->cmd);
130: pfl->wcycle = 0;
131: pfl->cmd = 0;
132: case 0x80:
133: /* We accept reads during second unlock sequence... */
134: case 0x00:
135: flash_read:
136: /* Flash area read */
137: p = pfl->storage;
138: switch (width) {
139: case 1:
140: ret = p[offset];
141: // DPRINTF("%s: data offset %08x %02x\n", __func__, offset, ret);
142: break;
143: case 2:
1.1.1.7 root 144: if (be) {
145: ret = p[offset] << 8;
146: ret |= p[offset + 1];
147: } else {
148: ret = p[offset];
149: ret |= p[offset + 1] << 8;
150: }
1.1 root 151: // DPRINTF("%s: data offset %08x %04x\n", __func__, offset, ret);
152: break;
153: case 4:
1.1.1.7 root 154: if (be) {
155: ret = p[offset] << 24;
156: ret |= p[offset + 1] << 16;
157: ret |= p[offset + 2] << 8;
158: ret |= p[offset + 3];
159: } else {
160: ret = p[offset];
161: ret |= p[offset + 1] << 8;
162: ret |= p[offset + 2] << 16;
163: ret |= p[offset + 3] << 24;
164: }
1.1 root 165: // DPRINTF("%s: data offset %08x %08x\n", __func__, offset, ret);
166: break;
167: }
168: break;
169: case 0x90:
170: /* flash ID read */
171: switch (boff) {
172: case 0x00:
173: case 0x01:
174: ret = pfl->ident[boff & 0x01];
175: break;
176: case 0x02:
177: ret = 0x00; /* Pretend all sectors are unprotected */
178: break;
179: case 0x0E:
180: case 0x0F:
181: if (pfl->ident[2 + (boff & 0x01)] == (uint8_t)-1)
182: goto flash_read;
183: ret = pfl->ident[2 + (boff & 0x01)];
184: break;
185: default:
186: goto flash_read;
187: }
1.1.1.7 root 188: DPRINTF("%s: ID " TARGET_FMT_pld " %x\n", __func__, boff, ret);
1.1 root 189: break;
190: case 0xA0:
191: case 0x10:
192: case 0x30:
193: /* Status register read */
194: ret = pfl->status;
195: DPRINTF("%s: status %x\n", __func__, ret);
196: /* Toggle bit 6 */
197: pfl->status ^= 0x40;
198: break;
199: case 0x98:
200: /* CFI query mode */
201: if (boff > pfl->cfi_len)
202: ret = 0;
203: else
204: ret = pfl->cfi_table[boff];
205: break;
206: }
207:
208: return ret;
209: }
210:
211: /* update flash content on disk */
1.1.1.3 root 212: static void pflash_update(pflash_t *pfl, int offset,
1.1 root 213: int size)
214: {
215: int offset_end;
216: if (pfl->bs) {
217: offset_end = offset + size;
218: /* round to sectors */
219: offset = offset >> 9;
220: offset_end = (offset_end + 511) >> 9;
1.1.1.3 root 221: bdrv_write(pfl->bs, offset, pfl->storage + (offset << 9),
1.1 root 222: offset_end - offset);
223: }
224: }
225:
1.1.1.7 root 226: static void pflash_write (pflash_t *pfl, target_phys_addr_t offset,
227: uint32_t value, int width, int be)
1.1 root 228: {
1.1.1.7 root 229: target_phys_addr_t boff;
1.1 root 230: uint8_t *p;
231: uint8_t cmd;
232:
233: cmd = value;
234: if (pfl->cmd != 0xA0 && cmd == 0xF0) {
1.1.1.3 root 235: #if 0
1.1 root 236: DPRINTF("%s: flash reset asked (%02x %02x)\n",
237: __func__, pfl->cmd, cmd);
1.1.1.3 root 238: #endif
1.1 root 239: goto reset_flash;
240: }
1.1.1.7 root 241: DPRINTF("%s: offset " TARGET_FMT_plx " %08x %d %d\n", __func__,
1.1.1.3 root 242: offset, value, width, pfl->wcycle);
1.1.1.4 root 243: offset &= pfl->chip_len - 1;
1.1.1.3 root 244:
1.1.1.7 root 245: DPRINTF("%s: offset " TARGET_FMT_plx " %08x %d\n", __func__,
1.1.1.3 root 246: offset, value, width);
1.1 root 247: boff = offset & (pfl->sector_len - 1);
248: if (pfl->width == 2)
249: boff = boff >> 1;
250: else if (pfl->width == 4)
251: boff = boff >> 2;
252: switch (pfl->wcycle) {
253: case 0:
1.1.1.4 root 254: /* Set the device in I/O access mode if required */
255: if (pfl->rom_mode)
256: pflash_register_memory(pfl, 0);
1.1 root 257: /* We're in read mode */
258: check_unlock0:
259: if (boff == 0x55 && cmd == 0x98) {
260: enter_CFI_mode:
261: /* Enter CFI query mode */
262: pfl->wcycle = 7;
263: pfl->cmd = 0x98;
264: return;
265: }
1.1.1.4 root 266: if (boff != pfl->unlock_addr[0] || cmd != 0xAA) {
1.1.1.7 root 267: DPRINTF("%s: unlock0 failed " TARGET_FMT_plx " %02x %04x\n",
1.1.1.4 root 268: __func__, boff, cmd, pfl->unlock_addr[0]);
1.1 root 269: goto reset_flash;
270: }
271: DPRINTF("%s: unlock sequence started\n", __func__);
272: break;
273: case 1:
274: /* We started an unlock sequence */
275: check_unlock1:
1.1.1.4 root 276: if (boff != pfl->unlock_addr[1] || cmd != 0x55) {
1.1.1.7 root 277: DPRINTF("%s: unlock1 failed " TARGET_FMT_plx " %02x\n", __func__,
1.1.1.3 root 278: boff, cmd);
1.1 root 279: goto reset_flash;
280: }
281: DPRINTF("%s: unlock sequence done\n", __func__);
282: break;
283: case 2:
284: /* We finished an unlock sequence */
1.1.1.4 root 285: if (!pfl->bypass && boff != pfl->unlock_addr[0]) {
1.1.1.7 root 286: DPRINTF("%s: command failed " TARGET_FMT_plx " %02x\n", __func__,
1.1.1.3 root 287: boff, cmd);
1.1 root 288: goto reset_flash;
289: }
290: switch (cmd) {
291: case 0x20:
292: pfl->bypass = 1;
293: goto do_bypass;
294: case 0x80:
295: case 0x90:
296: case 0xA0:
297: pfl->cmd = cmd;
298: DPRINTF("%s: starting command %02x\n", __func__, cmd);
299: break;
300: default:
301: DPRINTF("%s: unknown command %02x\n", __func__, cmd);
302: goto reset_flash;
303: }
304: break;
305: case 3:
306: switch (pfl->cmd) {
307: case 0x80:
308: /* We need another unlock sequence */
309: goto check_unlock0;
310: case 0xA0:
1.1.1.7 root 311: DPRINTF("%s: write data offset " TARGET_FMT_plx " %08x %d\n",
1.1 root 312: __func__, offset, value, width);
313: p = pfl->storage;
314: switch (width) {
315: case 1:
316: p[offset] &= value;
317: pflash_update(pfl, offset, 1);
318: break;
319: case 2:
1.1.1.7 root 320: if (be) {
321: p[offset] &= value >> 8;
322: p[offset + 1] &= value;
323: } else {
324: p[offset] &= value;
325: p[offset + 1] &= value >> 8;
326: }
1.1 root 327: pflash_update(pfl, offset, 2);
328: break;
329: case 4:
1.1.1.7 root 330: if (be) {
331: p[offset] &= value >> 24;
332: p[offset + 1] &= value >> 16;
333: p[offset + 2] &= value >> 8;
334: p[offset + 3] &= value;
335: } else {
336: p[offset] &= value;
337: p[offset + 1] &= value >> 8;
338: p[offset + 2] &= value >> 16;
339: p[offset + 3] &= value >> 24;
340: }
1.1 root 341: pflash_update(pfl, offset, 4);
342: break;
343: }
344: pfl->status = 0x00 | ~(value & 0x80);
345: /* Let's pretend write is immediate */
346: if (pfl->bypass)
347: goto do_bypass;
348: goto reset_flash;
349: case 0x90:
350: if (pfl->bypass && cmd == 0x00) {
351: /* Unlock bypass reset */
352: goto reset_flash;
353: }
354: /* We can enter CFI query mode from autoselect mode */
355: if (boff == 0x55 && cmd == 0x98)
356: goto enter_CFI_mode;
357: /* No break here */
358: default:
359: DPRINTF("%s: invalid write for command %02x\n",
360: __func__, pfl->cmd);
361: goto reset_flash;
362: }
363: case 4:
364: switch (pfl->cmd) {
365: case 0xA0:
366: /* Ignore writes while flash data write is occuring */
367: /* As we suppose write is immediate, this should never happen */
368: return;
369: case 0x80:
370: goto check_unlock1;
371: default:
372: /* Should never happen */
373: DPRINTF("%s: invalid command state %02x (wc 4)\n",
374: __func__, pfl->cmd);
375: goto reset_flash;
376: }
377: break;
378: case 5:
379: switch (cmd) {
380: case 0x10:
1.1.1.4 root 381: if (boff != pfl->unlock_addr[0]) {
1.1.1.7 root 382: DPRINTF("%s: chip erase: invalid address " TARGET_FMT_plx "\n",
1.1 root 383: __func__, offset);
384: goto reset_flash;
385: }
386: /* Chip erase */
387: DPRINTF("%s: start chip erase\n", __func__);
1.1.1.4 root 388: memset(pfl->storage, 0xFF, pfl->chip_len);
1.1 root 389: pfl->status = 0x00;
1.1.1.4 root 390: pflash_update(pfl, 0, pfl->chip_len);
1.1 root 391: /* Let's wait 5 seconds before chip erase is done */
1.1.1.3 root 392: qemu_mod_timer(pfl->timer,
1.1.1.6 root 393: qemu_get_clock(vm_clock) + (get_ticks_per_sec() * 5));
1.1 root 394: break;
395: case 0x30:
396: /* Sector erase */
397: p = pfl->storage;
398: offset &= ~(pfl->sector_len - 1);
1.1.1.7 root 399: DPRINTF("%s: start sector erase at " TARGET_FMT_plx "\n", __func__,
1.1.1.3 root 400: offset);
1.1 root 401: memset(p + offset, 0xFF, pfl->sector_len);
402: pflash_update(pfl, offset, pfl->sector_len);
403: pfl->status = 0x00;
404: /* Let's wait 1/2 second before sector erase is done */
1.1.1.3 root 405: qemu_mod_timer(pfl->timer,
1.1.1.6 root 406: qemu_get_clock(vm_clock) + (get_ticks_per_sec() / 2));
1.1 root 407: break;
408: default:
409: DPRINTF("%s: invalid command %02x (wc 5)\n", __func__, cmd);
410: goto reset_flash;
411: }
412: pfl->cmd = cmd;
413: break;
414: case 6:
415: switch (pfl->cmd) {
416: case 0x10:
417: /* Ignore writes during chip erase */
418: return;
419: case 0x30:
420: /* Ignore writes during sector erase */
421: return;
422: default:
423: /* Should never happen */
424: DPRINTF("%s: invalid command state %02x (wc 6)\n",
425: __func__, pfl->cmd);
426: goto reset_flash;
427: }
428: break;
429: case 7: /* Special value for CFI queries */
430: DPRINTF("%s: invalid write in CFI query mode\n", __func__);
431: goto reset_flash;
432: default:
433: /* Should never happen */
434: DPRINTF("%s: invalid write state (wc 7)\n", __func__);
435: goto reset_flash;
436: }
437: pfl->wcycle++;
438:
439: return;
440:
441: /* Reset flash */
442: reset_flash:
443: pfl->bypass = 0;
444: pfl->wcycle = 0;
445: pfl->cmd = 0;
446: return;
447:
448: do_bypass:
449: pfl->wcycle = 2;
450: pfl->cmd = 0;
451: return;
452: }
453:
454:
1.1.1.7 root 455: static uint32_t pflash_readb_be(void *opaque, target_phys_addr_t addr)
456: {
457: return pflash_read(opaque, addr, 1, 1);
458: }
459:
460: static uint32_t pflash_readb_le(void *opaque, target_phys_addr_t addr)
1.1 root 461: {
1.1.1.7 root 462: return pflash_read(opaque, addr, 1, 0);
1.1 root 463: }
464:
1.1.1.7 root 465: static uint32_t pflash_readw_be(void *opaque, target_phys_addr_t addr)
1.1 root 466: {
467: pflash_t *pfl = opaque;
468:
1.1.1.7 root 469: return pflash_read(pfl, addr, 2, 1);
1.1 root 470: }
471:
1.1.1.7 root 472: static uint32_t pflash_readw_le(void *opaque, target_phys_addr_t addr)
1.1 root 473: {
474: pflash_t *pfl = opaque;
475:
1.1.1.7 root 476: return pflash_read(pfl, addr, 2, 0);
1.1 root 477: }
478:
1.1.1.7 root 479: static uint32_t pflash_readl_be(void *opaque, target_phys_addr_t addr)
1.1 root 480: {
1.1.1.7 root 481: pflash_t *pfl = opaque;
482:
483: return pflash_read(pfl, addr, 4, 1);
1.1 root 484: }
485:
1.1.1.7 root 486: static uint32_t pflash_readl_le(void *opaque, target_phys_addr_t addr)
1.1 root 487: {
488: pflash_t *pfl = opaque;
489:
1.1.1.7 root 490: return pflash_read(pfl, addr, 4, 0);
491: }
492:
493: static void pflash_writeb_be(void *opaque, target_phys_addr_t addr,
494: uint32_t value)
495: {
496: pflash_write(opaque, addr, value, 1, 1);
1.1 root 497: }
498:
1.1.1.7 root 499: static void pflash_writeb_le(void *opaque, target_phys_addr_t addr,
500: uint32_t value)
501: {
502: pflash_write(opaque, addr, value, 1, 0);
503: }
504:
505: static void pflash_writew_be(void *opaque, target_phys_addr_t addr,
506: uint32_t value)
507: {
508: pflash_t *pfl = opaque;
509:
510: pflash_write(pfl, addr, value, 2, 1);
511: }
512:
513: static void pflash_writew_le(void *opaque, target_phys_addr_t addr,
514: uint32_t value)
1.1 root 515: {
516: pflash_t *pfl = opaque;
517:
1.1.1.7 root 518: pflash_write(pfl, addr, value, 2, 0);
1.1 root 519: }
520:
1.1.1.7 root 521: static void pflash_writel_be(void *opaque, target_phys_addr_t addr,
522: uint32_t value)
523: {
524: pflash_t *pfl = opaque;
525:
526: pflash_write(pfl, addr, value, 4, 1);
527: }
528:
529: static void pflash_writel_le(void *opaque, target_phys_addr_t addr,
530: uint32_t value)
531: {
532: pflash_t *pfl = opaque;
533:
534: pflash_write(pfl, addr, value, 4, 0);
535: }
536:
537: static CPUWriteMemoryFunc * const pflash_write_ops_be[] = {
538: &pflash_writeb_be,
539: &pflash_writew_be,
540: &pflash_writel_be,
541: };
542:
543: static CPUReadMemoryFunc * const pflash_read_ops_be[] = {
544: &pflash_readb_be,
545: &pflash_readw_be,
546: &pflash_readl_be,
1.1 root 547: };
548:
1.1.1.7 root 549: static CPUWriteMemoryFunc * const pflash_write_ops_le[] = {
550: &pflash_writeb_le,
551: &pflash_writew_le,
552: &pflash_writel_le,
553: };
554:
555: static CPUReadMemoryFunc * const pflash_read_ops_le[] = {
556: &pflash_readb_le,
557: &pflash_readw_le,
558: &pflash_readl_le,
1.1 root 559: };
560:
561: /* Count trailing zeroes of a 32 bits quantity */
562: static int ctz32 (uint32_t n)
563: {
564: int ret;
565:
566: ret = 0;
567: if (!(n & 0xFFFF)) {
568: ret += 16;
569: n = n >> 16;
570: }
571: if (!(n & 0xFF)) {
572: ret += 8;
573: n = n >> 8;
574: }
575: if (!(n & 0xF)) {
576: ret += 4;
577: n = n >> 4;
578: }
579: if (!(n & 0x3)) {
580: ret += 2;
581: n = n >> 2;
582: }
583: if (!(n & 0x1)) {
584: ret++;
1.1.1.7 root 585: #if 0 /* This is not necessary as n is never 0 */
1.1 root 586: n = n >> 1;
1.1.1.7 root 587: #endif
1.1 root 588: }
589: #if 0 /* This is not necessary as n is never 0 */
590: if (!n)
591: ret++;
592: #endif
593:
594: return ret;
595: }
596:
1.1.1.3 root 597: pflash_t *pflash_cfi02_register(target_phys_addr_t base, ram_addr_t off,
598: BlockDriverState *bs, uint32_t sector_len,
1.1.1.4 root 599: int nb_blocs, int nb_mappings, int width,
1.1.1.3 root 600: uint16_t id0, uint16_t id1,
1.1.1.4 root 601: uint16_t id2, uint16_t id3,
1.1.1.7 root 602: uint16_t unlock_addr0, uint16_t unlock_addr1,
603: int be)
1.1 root 604: {
605: pflash_t *pfl;
1.1.1.4 root 606: int32_t chip_len;
1.1.1.6 root 607: int ret;
1.1 root 608:
1.1.1.4 root 609: chip_len = sector_len * nb_blocs;
1.1 root 610: /* XXX: to be fixed */
1.1.1.3 root 611: #if 0
1.1 root 612: if (total_len != (8 * 1024 * 1024) && total_len != (16 * 1024 * 1024) &&
613: total_len != (32 * 1024 * 1024) && total_len != (64 * 1024 * 1024))
614: return NULL;
1.1.1.3 root 615: #endif
1.1 root 616: pfl = qemu_mallocz(sizeof(pflash_t));
1.1.1.5 root 617: /* FIXME: Allocate ram ourselves. */
618: pfl->storage = qemu_get_ram_ptr(off);
1.1.1.7 root 619: if (be) {
620: pfl->fl_mem = cpu_register_io_memory(pflash_read_ops_be,
621: pflash_write_ops_be,
1.1.1.8 ! root 622: pfl, DEVICE_NATIVE_ENDIAN);
1.1.1.7 root 623: } else {
624: pfl->fl_mem = cpu_register_io_memory(pflash_read_ops_le,
625: pflash_write_ops_le,
1.1.1.8 ! root 626: pfl, DEVICE_NATIVE_ENDIAN);
1.1.1.7 root 627: }
1.1 root 628: pfl->off = off;
1.1.1.4 root 629: pfl->base = base;
630: pfl->chip_len = chip_len;
631: pfl->mappings = nb_mappings;
632: pflash_register_memory(pfl, 1);
1.1 root 633: pfl->bs = bs;
634: if (pfl->bs) {
635: /* read the initial flash content */
1.1.1.6 root 636: ret = bdrv_read(pfl->bs, 0, pfl->storage, chip_len >> 9);
637: if (ret < 0) {
638: cpu_unregister_io_memory(pfl->fl_mem);
639: qemu_free(pfl);
640: return NULL;
641: }
1.1 root 642: }
643: #if 0 /* XXX: there should be a bit to set up read-only,
644: * the same way the hardware does (with WP pin).
645: */
646: pfl->ro = 1;
647: #else
648: pfl->ro = 0;
649: #endif
650: pfl->timer = qemu_new_timer(vm_clock, pflash_timer, pfl);
651: pfl->sector_len = sector_len;
652: pfl->width = width;
653: pfl->wcycle = 0;
654: pfl->cmd = 0;
655: pfl->status = 0;
656: pfl->ident[0] = id0;
657: pfl->ident[1] = id1;
658: pfl->ident[2] = id2;
659: pfl->ident[3] = id3;
1.1.1.4 root 660: pfl->unlock_addr[0] = unlock_addr0;
661: pfl->unlock_addr[1] = unlock_addr1;
1.1 root 662: /* Hardcoded CFI table (mostly from SG29 Spansion flash) */
663: pfl->cfi_len = 0x52;
664: /* Standard "QRY" string */
665: pfl->cfi_table[0x10] = 'Q';
666: pfl->cfi_table[0x11] = 'R';
667: pfl->cfi_table[0x12] = 'Y';
668: /* Command set (AMD/Fujitsu) */
669: pfl->cfi_table[0x13] = 0x02;
670: pfl->cfi_table[0x14] = 0x00;
1.1.1.4 root 671: /* Primary extended table address */
672: pfl->cfi_table[0x15] = 0x31;
1.1 root 673: pfl->cfi_table[0x16] = 0x00;
674: /* Alternate command set (none) */
675: pfl->cfi_table[0x17] = 0x00;
676: pfl->cfi_table[0x18] = 0x00;
677: /* Alternate extended table (none) */
678: pfl->cfi_table[0x19] = 0x00;
679: pfl->cfi_table[0x1A] = 0x00;
680: /* Vcc min */
681: pfl->cfi_table[0x1B] = 0x27;
682: /* Vcc max */
683: pfl->cfi_table[0x1C] = 0x36;
684: /* Vpp min (no Vpp pin) */
685: pfl->cfi_table[0x1D] = 0x00;
686: /* Vpp max (no Vpp pin) */
687: pfl->cfi_table[0x1E] = 0x00;
688: /* Reserved */
689: pfl->cfi_table[0x1F] = 0x07;
1.1.1.4 root 690: /* Timeout for min size buffer write (NA) */
691: pfl->cfi_table[0x20] = 0x00;
1.1 root 692: /* Typical timeout for block erase (512 ms) */
693: pfl->cfi_table[0x21] = 0x09;
694: /* Typical timeout for full chip erase (4096 ms) */
695: pfl->cfi_table[0x22] = 0x0C;
696: /* Reserved */
697: pfl->cfi_table[0x23] = 0x01;
1.1.1.4 root 698: /* Max timeout for buffer write (NA) */
699: pfl->cfi_table[0x24] = 0x00;
1.1 root 700: /* Max timeout for block erase */
701: pfl->cfi_table[0x25] = 0x0A;
702: /* Max timeout for chip erase */
703: pfl->cfi_table[0x26] = 0x0D;
704: /* Device size */
1.1.1.4 root 705: pfl->cfi_table[0x27] = ctz32(chip_len);
1.1 root 706: /* Flash device interface (8 & 16 bits) */
707: pfl->cfi_table[0x28] = 0x02;
708: pfl->cfi_table[0x29] = 0x00;
709: /* Max number of bytes in multi-bytes write */
1.1.1.3 root 710: /* XXX: disable buffered write as it's not supported */
711: // pfl->cfi_table[0x2A] = 0x05;
712: pfl->cfi_table[0x2A] = 0x00;
1.1 root 713: pfl->cfi_table[0x2B] = 0x00;
714: /* Number of erase block regions (uniform) */
715: pfl->cfi_table[0x2C] = 0x01;
716: /* Erase block region 1 */
717: pfl->cfi_table[0x2D] = nb_blocs - 1;
718: pfl->cfi_table[0x2E] = (nb_blocs - 1) >> 8;
719: pfl->cfi_table[0x2F] = sector_len >> 8;
720: pfl->cfi_table[0x30] = sector_len >> 16;
721:
1.1.1.4 root 722: /* Extended */
723: pfl->cfi_table[0x31] = 'P';
724: pfl->cfi_table[0x32] = 'R';
725: pfl->cfi_table[0x33] = 'I';
726:
727: pfl->cfi_table[0x34] = '1';
728: pfl->cfi_table[0x35] = '0';
729:
730: pfl->cfi_table[0x36] = 0x00;
731: pfl->cfi_table[0x37] = 0x00;
732: pfl->cfi_table[0x38] = 0x00;
733: pfl->cfi_table[0x39] = 0x00;
734:
735: pfl->cfi_table[0x3a] = 0x00;
736:
737: pfl->cfi_table[0x3b] = 0x00;
738: pfl->cfi_table[0x3c] = 0x00;
739:
1.1 root 740: return pfl;
741: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.