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