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