]> Git Repo - qemu.git/blob - hw/pflash_cfi01.c
vmstate, memory: decouple vmstate from memory API
[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 + 1] << 8;
148                 ret |= p[offset + 2] << 16;
149                 ret |= p[offset + 3] << 24;
150             }
151             DPRINTF("%s: data offset " TARGET_FMT_plx " %08x\n",
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;
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;
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
214 static inline void pflash_data_write(pflash_t *pfl, target_phys_addr_t offset,
215                                      uint32_t value, int width, int be)
216 {
217     uint8_t *p = pfl->storage;
218
219     DPRINTF("%s: block write offset " TARGET_FMT_plx
220             " value %x counter " TARGET_FMT_plx "\n",
221             __func__, offset, value, pfl->counter);
222     switch (width) {
223     case 1:
224         p[offset] = value;
225         break;
226     case 2:
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         }
234         break;
235     case 4:
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         }
247         break;
248     }
249
250 }
251
252 static void pflash_write(pflash_t *pfl, target_phys_addr_t offset,
253                          uint32_t value, int width, int be)
254 {
255     uint8_t *p;
256     uint8_t cmd;
257
258     cmd = value;
259
260     DPRINTF("%s: writing offset " TARGET_FMT_plx " value %08x width %d wcycle 0x%x\n",
261             __func__, offset, value, width, pfl->wcycle);
262
263     if (!pfl->wcycle) {
264         /* Set the device in I/O access mode */
265         memory_region_rom_device_set_readable(&pfl->mem, false);
266     }
267
268     switch (pfl->wcycle) {
269     case 0:
270         /* read mode */
271         switch (cmd) {
272         case 0x00: /* ??? */
273             goto reset_flash;
274         case 0x10: /* Single Byte Program */
275         case 0x40: /* Single Byte Program */
276             DPRINTF("%s: Single Byte Program\n", __func__);
277             break;
278         case 0x20: /* Block erase */
279             p = pfl->storage;
280             offset &= ~(pfl->sector_len - 1);
281
282             DPRINTF("%s: block erase at " TARGET_FMT_plx " bytes "
283                     TARGET_FMT_plx "\n",
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;
301         case 0x90: /* Read Device ID */
302             DPRINTF("%s: Read Device information\n", __func__);
303             pfl->cmd = cmd;
304             return;
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) {
323         case 0x10: /* Single Byte Program */
324         case 0x40: /* Single Byte Program */
325             DPRINTF("%s: Single Byte Program\n", __func__);
326             pflash_data_write(pfl, offset, value, width, be);
327             pflash_update(pfl, offset, width);
328             pfl->status |= 0x80; /* Ready! */
329             pfl->wcycle = 0;
330         break;
331         case 0x20: /* Block erase */
332         case 0x28:
333             if (cmd == 0xd0) { /* confirm */
334                 pfl->wcycle = 0;
335                 pfl->status |= 0x80;
336             } else if (cmd == 0xff) { /* read array mode */
337                 goto reset_flash;
338             } else
339                 goto error_flash;
340
341             break;
342         case 0xe8:
343             DPRINTF("%s: block write of %x bytes\n", __func__, value);
344             pfl->counter = value;
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 */
375             pflash_data_write(pfl, offset, value, width, be);
376
377             pfl->status |= 0x80;
378
379             if (!pfl->counter) {
380                 target_phys_addr_t mask = pfl->writeblock_size - 1;
381                 mask = ~mask;
382
383                 DPRINTF("%s: block write finished\n", __func__);
384                 pfl->wcycle++;
385                 /* Flush the entire write buffer onto backing storage.  */
386                 pflash_update(pfl, offset & mask, pfl->writeblock_size);
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 "
420            "(offset " TARGET_FMT_plx ", wcycle 0x%x cmd 0x%x value 0x%x)\n",
421            __func__, offset, pfl->wcycle, pfl->cmd, value);
422
423  reset_flash:
424     memory_region_rom_device_set_readable(&pfl->mem, true);
425
426     pfl->bypass = 0;
427     pfl->wcycle = 0;
428     pfl->cmd = 0;
429     return;
430 }
431
432
433 static uint32_t pflash_readb_be(void *opaque, target_phys_addr_t addr)
434 {
435     return pflash_read(opaque, addr, 1, 1);
436 }
437
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)
458 {
459     pflash_t *pfl = opaque;
460
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);
481 }
482
483 static void pflash_writew_be(void *opaque, target_phys_addr_t addr,
484                              uint32_t value)
485 {
486     pflash_t *pfl = opaque;
487
488     pflash_write(pfl, addr, value, 2, 1);
489 }
490
491 static void pflash_writew_le(void *opaque, target_phys_addr_t addr,
492                              uint32_t value)
493 {
494     pflash_t *pfl = opaque;
495
496     pflash_write(pfl, addr, value, 2, 0);
497 }
498
499 static void pflash_writel_be(void *opaque, target_phys_addr_t addr,
500                              uint32_t value)
501 {
502     pflash_t *pfl = opaque;
503
504     pflash_write(pfl, addr, value, 4, 1);
505 }
506
507 static void pflash_writel_le(void *opaque, target_phys_addr_t addr,
508                              uint32_t value)
509 {
510     pflash_t *pfl = opaque;
511
512     pflash_write(pfl, addr, value, 4, 0);
513 }
514
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,
521 };
522
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,
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++;
555 #if 0 /* This is not necessary as n is never 0 */
556         n = n >> 1;
557 #endif
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
567 pflash_t *pflash_cfi01_register(target_phys_addr_t base,
568                                 DeviceState *qdev, const char *name,
569                                 target_phys_addr_t size,
570                                 BlockDriverState *bs, uint32_t sector_len,
571                                 int nb_blocs, int width,
572                                 uint16_t id0, uint16_t id1,
573                                 uint16_t id2, uint16_t id3, int be)
574 {
575     pflash_t *pfl;
576     target_phys_addr_t total_len;
577     int ret;
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
588     pfl = g_malloc0(sizeof(pflash_t));
589
590     memory_region_init_rom_device(
591         &pfl->mem, be ? &pflash_cfi01_ops_be : &pflash_cfi01_ops_le, pfl,
592         name, size);
593     vmstate_register_ram(&pfl->mem, qdev);
594     pfl->storage = memory_region_get_ram_ptr(&pfl->mem);
595     memory_region_add_subregion(get_system_memory(), base, &pfl->mem);
596
597     pfl->bs = bs;
598     if (pfl->bs) {
599         /* read the initial flash content */
600         ret = bdrv_read(pfl->bs, 0, pfl->storage, total_len >> 9);
601         if (ret < 0) {
602             memory_region_del_subregion(get_system_memory(), &pfl->mem);
603             vmstate_unregister_ram(&pfl->mem, qdev);
604             memory_region_destroy(&pfl->mem);
605             g_free(pfl);
606             return NULL;
607         }
608         bdrv_attach_dev_nofail(pfl->bs, pfl);
609     }
610 #if 0 /* XXX: there should be a bit to set up read-only,
611        *      the same way the hardware does (with WP pin).
612        */
613     pfl->ro = 1;
614 #else
615     pfl->ro = 0;
616 #endif
617     pfl->timer = qemu_new_timer_ns(vm_clock, pflash_timer, pfl);
618     pfl->base = base;
619     pfl->sector_len = sector_len;
620     pfl->total_len = total_len;
621     pfl->width = width;
622     pfl->wcycle = 0;
623     pfl->cmd = 0;
624     pfl->status = 0;
625     pfl->ident[0] = id0;
626     pfl->ident[1] = id1;
627     pfl->ident[2] = id2;
628     pfl->ident[3] = id3;
629     /* Hardcoded CFI table */
630     pfl->cfi_len = 0x52;
631     /* Standard "QRY" string */
632     pfl->cfi_table[0x10] = 'Q';
633     pfl->cfi_table[0x11] = 'R';
634     pfl->cfi_table[0x12] = 'Y';
635     /* Command set (Intel) */
636     pfl->cfi_table[0x13] = 0x01;
637     pfl->cfi_table[0x14] = 0x00;
638     /* Primary extended table address (none) */
639     pfl->cfi_table[0x15] = 0x31;
640     pfl->cfi_table[0x16] = 0x00;
641     /* Alternate command set (none) */
642     pfl->cfi_table[0x17] = 0x00;
643     pfl->cfi_table[0x18] = 0x00;
644     /* Alternate extended table (none) */
645     pfl->cfi_table[0x19] = 0x00;
646     pfl->cfi_table[0x1A] = 0x00;
647     /* Vcc min */
648     pfl->cfi_table[0x1B] = 0x45;
649     /* Vcc max */
650     pfl->cfi_table[0x1C] = 0x55;
651     /* Vpp min (no Vpp pin) */
652     pfl->cfi_table[0x1D] = 0x00;
653     /* Vpp max (no Vpp pin) */
654     pfl->cfi_table[0x1E] = 0x00;
655     /* Reserved */
656     pfl->cfi_table[0x1F] = 0x07;
657     /* Timeout for min size buffer write */
658     pfl->cfi_table[0x20] = 0x07;
659     /* Typical timeout for block erase */
660     pfl->cfi_table[0x21] = 0x0a;
661     /* Typical timeout for full chip erase (4096 ms) */
662     pfl->cfi_table[0x22] = 0x00;
663     /* Reserved */
664     pfl->cfi_table[0x23] = 0x04;
665     /* Max timeout for buffer write */
666     pfl->cfi_table[0x24] = 0x04;
667     /* Max timeout for block erase */
668     pfl->cfi_table[0x25] = 0x04;
669     /* Max timeout for chip erase */
670     pfl->cfi_table[0x26] = 0x00;
671     /* Device size */
672     pfl->cfi_table[0x27] = ctz32(total_len); // + 1;
673     /* Flash device interface (8 & 16 bits) */
674     pfl->cfi_table[0x28] = 0x02;
675     pfl->cfi_table[0x29] = 0x00;
676     /* Max number of bytes in multi-bytes write */
677     if (width == 1) {
678         pfl->cfi_table[0x2A] = 0x08;
679     } else {
680         pfl->cfi_table[0x2A] = 0x0B;
681     }
682     pfl->writeblock_size = 1 << pfl->cfi_table[0x2A];
683
684     pfl->cfi_table[0x2B] = 0x00;
685     /* Number of erase block regions (uniform) */
686     pfl->cfi_table[0x2C] = 0x01;
687     /* Erase block region 1 */
688     pfl->cfi_table[0x2D] = nb_blocs - 1;
689     pfl->cfi_table[0x2E] = (nb_blocs - 1) >> 8;
690     pfl->cfi_table[0x2F] = sector_len >> 8;
691     pfl->cfi_table[0x30] = sector_len >> 16;
692
693     /* Extended */
694     pfl->cfi_table[0x31] = 'P';
695     pfl->cfi_table[0x32] = 'R';
696     pfl->cfi_table[0x33] = 'I';
697
698     pfl->cfi_table[0x34] = '1';
699     pfl->cfi_table[0x35] = '1';
700
701     pfl->cfi_table[0x36] = 0x00;
702     pfl->cfi_table[0x37] = 0x00;
703     pfl->cfi_table[0x38] = 0x00;
704     pfl->cfi_table[0x39] = 0x00;
705
706     pfl->cfi_table[0x3a] = 0x00;
707
708     pfl->cfi_table[0x3b] = 0x00;
709     pfl->cfi_table[0x3c] = 0x00;
710
711     return pfl;
712 }
713
714 MemoryRegion *pflash_cfi01_get_memory(pflash_t *fl)
715 {
716     return &fl->mem;
717 }
This page took 0.065134 seconds and 4 git commands to generate.