Tizen 2.1 base
[sdk/emulator/qemu.git] / hw / pflash_cfi01.c
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
18  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
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 #include "exec-memory.h"
44
45 #define PFLASH_BUG(fmt, ...) \
46 do { \
47     printf("PFLASH: Possible BUG - " fmt, ## __VA_ARGS__); \
48     exit(1); \
49 } while(0)
50
51 /* #define PFLASH_DEBUG */
52 #ifdef PFLASH_DEBUG
53 #define DPRINTF(fmt, ...)                          \
54 do {                                               \
55     printf("PFLASH: " fmt , ## __VA_ARGS__);       \
56 } while (0)
57 #else
58 #define DPRINTF(fmt, ...) do { } while (0)
59 #endif
60
61 struct pflash_t {
62     BlockDriverState *bs;
63     target_phys_addr_t base;
64     target_phys_addr_t sector_len;
65     target_phys_addr_t total_len;
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];
75     target_phys_addr_t counter;
76     unsigned int writeblock_size;
77     QEMUTimer *timer;
78     MemoryRegion 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         memory_region_rom_device_set_readable(&pfl->mem, true);
93         pfl->wcycle = 0;
94     }
95     pfl->cmd = 0;
96 }
97
98 static uint32_t pflash_read (pflash_t *pfl, target_phys_addr_t offset,
99                              int width, int be)
100 {
101     target_phys_addr_t boff;
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
113 #if 0
114     DPRINTF("%s: reading offset " TARGET_FMT_plx " under cmd %02x width %d\n",
115             __func__, offset, pfl->cmd, width);
116 #endif
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];
124             DPRINTF("%s: data offset " TARGET_FMT_plx " %02x\n",
125                     __func__, offset, ret);
126             break;
127         case 2:
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             }
135             DPRINTF("%s: data offset " TARGET_FMT_plx " %04x\n",
136                     __func__, offset, ret);
137             break;
138         case 4:
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             }
150             DPRINTF("%s: data offset " TARGET_FMT_plx " %08x\n",
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;
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;
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
213 static inline void pflash_data_write(pflash_t *pfl, target_phys_addr_t offset,
214                                      uint32_t value, int width, int be)
215 {
216     uint8_t *p = pfl->storage;
217
218     DPRINTF("%s: block write offset " TARGET_FMT_plx
219             " value %x counter " TARGET_FMT_plx "\n",
220             __func__, offset, value, pfl->counter);
221     switch (width) {
222     case 1:
223         p[offset] = value;
224         break;
225     case 2:
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         }
233         break;
234     case 4:
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         }
246         break;
247     }
248
249 }
250
251 static void pflash_write(pflash_t *pfl, target_phys_addr_t offset,
252                          uint32_t value, int width, int be)
253 {
254     uint8_t *p;
255     uint8_t cmd;
256
257     cmd = value;
258
259     DPRINTF("%s: writing offset " TARGET_FMT_plx " value %08x width %d wcycle 0x%x\n",
260             __func__, offset, value, width, pfl->wcycle);
261
262     if (!pfl->wcycle) {
263         /* Set the device in I/O access mode */
264         memory_region_rom_device_set_readable(&pfl->mem, false);
265     }
266
267     switch (pfl->wcycle) {
268     case 0:
269         /* read mode */
270         switch (cmd) {
271         case 0x00: /* ??? */
272             goto reset_flash;
273         case 0x10: /* Single Byte Program */
274         case 0x40: /* Single Byte Program */
275             DPRINTF("%s: Single Byte Program\n", __func__);
276             break;
277         case 0x20: /* Block erase */
278             p = pfl->storage;
279             offset &= ~(pfl->sector_len - 1);
280
281             DPRINTF("%s: block erase at " TARGET_FMT_plx " bytes "
282                     TARGET_FMT_plx "\n",
283                     __func__, offset, pfl->sector_len);
284
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             }
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;
304         case 0x90: /* Read Device ID */
305             DPRINTF("%s: Read Device information\n", __func__);
306             pfl->cmd = cmd;
307             return;
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) {
326         case 0x10: /* Single Byte Program */
327         case 0x40: /* Single Byte Program */
328             DPRINTF("%s: Single Byte Program\n", __func__);
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             }
335             pfl->status |= 0x80; /* Ready! */
336             pfl->wcycle = 0;
337         break;
338         case 0x20: /* Block erase */
339         case 0x28:
340             if (cmd == 0xd0) { /* confirm */
341                 pfl->wcycle = 0;
342                 pfl->status |= 0x80;
343             } else if (cmd == 0xff) { /* read array mode */
344                 goto reset_flash;
345             } else
346                 goto error_flash;
347
348             break;
349         case 0xe8:
350             DPRINTF("%s: block write of %x bytes\n", __func__, value);
351             pfl->counter = value;
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 */
382             if (!pfl->ro) {
383                 pflash_data_write(pfl, offset, value, width, be);
384             } else {
385                 pfl->status |= 0x10; /* Programming error */
386             }
387
388             pfl->status |= 0x80;
389
390             if (!pfl->counter) {
391                 target_phys_addr_t mask = pfl->writeblock_size - 1;
392                 mask = ~mask;
393
394                 DPRINTF("%s: block write finished\n", __func__);
395                 pfl->wcycle++;
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                 }
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 "
435            "(offset " TARGET_FMT_plx ", wcycle 0x%x cmd 0x%x value 0x%x)\n",
436            __func__, offset, pfl->wcycle, pfl->cmd, value);
437
438  reset_flash:
439     memory_region_rom_device_set_readable(&pfl->mem, true);
440
441     pfl->bypass = 0;
442     pfl->wcycle = 0;
443     pfl->cmd = 0;
444     return;
445 }
446
447
448 static uint32_t pflash_readb_be(void *opaque, target_phys_addr_t addr)
449 {
450     return pflash_read(opaque, addr, 1, 1);
451 }
452
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)
473 {
474     pflash_t *pfl = opaque;
475
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);
496 }
497
498 static void pflash_writew_be(void *opaque, target_phys_addr_t addr,
499                              uint32_t value)
500 {
501     pflash_t *pfl = opaque;
502
503     pflash_write(pfl, addr, value, 2, 1);
504 }
505
506 static void pflash_writew_le(void *opaque, target_phys_addr_t addr,
507                              uint32_t value)
508 {
509     pflash_t *pfl = opaque;
510
511     pflash_write(pfl, addr, value, 2, 0);
512 }
513
514 static void pflash_writel_be(void *opaque, target_phys_addr_t addr,
515                              uint32_t value)
516 {
517     pflash_t *pfl = opaque;
518
519     pflash_write(pfl, addr, value, 4, 1);
520 }
521
522 static void pflash_writel_le(void *opaque, target_phys_addr_t addr,
523                              uint32_t value)
524 {
525     pflash_t *pfl = opaque;
526
527     pflash_write(pfl, addr, value, 4, 0);
528 }
529
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,
536 };
537
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,
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++;
570 #if 0 /* This is not necessary as n is never 0 */
571         n = n >> 1;
572 #endif
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
582 pflash_t *pflash_cfi01_register(target_phys_addr_t base,
583                                 DeviceState *qdev, const char *name,
584                                 target_phys_addr_t size,
585                                 BlockDriverState *bs, uint32_t sector_len,
586                                 int nb_blocs, int width,
587                                 uint16_t id0, uint16_t id1,
588                                 uint16_t id2, uint16_t id3, int be)
589 {
590     pflash_t *pfl;
591     target_phys_addr_t total_len;
592     int ret;
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
603     pfl = g_malloc0(sizeof(pflash_t));
604
605     memory_region_init_rom_device(
606         &pfl->mem, be ? &pflash_cfi01_ops_be : &pflash_cfi01_ops_le, pfl,
607         name, size);
608     vmstate_register_ram(&pfl->mem, qdev);
609     pfl->storage = memory_region_get_ram_ptr(&pfl->mem);
610     memory_region_add_subregion(get_system_memory(), base, &pfl->mem);
611
612     pfl->bs = bs;
613     if (pfl->bs) {
614         /* read the initial flash content */
615         ret = bdrv_read(pfl->bs, 0, pfl->storage, total_len >> 9);
616         if (ret < 0) {
617             memory_region_del_subregion(get_system_memory(), &pfl->mem);
618             vmstate_unregister_ram(&pfl->mem, qdev);
619             memory_region_destroy(&pfl->mem);
620             g_free(pfl);
621             return NULL;
622         }
623         bdrv_attach_dev_nofail(pfl->bs, pfl);
624     }
625
626     if (pfl->bs) {
627         pfl->ro = bdrv_is_read_only(pfl->bs);
628     } else {
629         pfl->ro = 0;
630     }
631
632     pfl->timer = qemu_new_timer_ns(vm_clock, pflash_timer, pfl);
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 */
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
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 }
728
729 MemoryRegion *pflash_cfi01_get_memory(pflash_t *fl)
730 {
731     return &fl->mem;
732 }