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