Update GitHub action for new Meson based build
[qemu/ar7.git] / hw / block / pflash_amd.c
blob39e74cc5dbe234452d2bb1eea966f5bcf492f453
1 /*
2 * CFI parallel flash with AMD / Fujitsu command set emulation
4 * Copyright (c) 2005 Jocelyn Mayer
5 * Copyright (c) 2006 Stefan Weil (ES29LV160DB emulation)
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.
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.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 * For now, this code can emulate flashes of 1, 2 or 4 bytes width.
24 * Supported commands/modes are:
25 * - flash read
26 * - flash write
27 * - flash ID read
28 * - sector erase
29 * - chip erase
30 * - unlock bypass command
31 * - CFI queries
33 * It does not support flash interleaving.
34 * It does not implement boot blocs with reduced size
35 * It does not implement software data protection as found in many real chips
36 * It does not implement erase suspend/resume commands
37 * It does not implement multiple sectors erase
39 * TODO:
40 * Support little endianness.
43 #include "qemu/osdep.h"
45 #include "hw.h"
46 #include "block/block.h"
47 #include "flash.h"
48 #include "pflash.h" /* pflash_amd_register */
49 #include "qemu&timer.h"
50 #include "exec-all.h"
52 #ifdef PFLASH_DEBUG
53 static int traceflag;
54 #define loglevel 1
55 #define logfile stderr
56 #define DPRINTF(fmt, ...) \
57 ((loglevel) ? fprintf(logfile, "PFLASH\t%-24s" fmt , __func__, ##__VA_ARGS__) : (void)0)
58 #else
59 #define DPRINTF(fmt, ...) do { } while (0)
60 #endif
62 typedef enum {
63 unknown_mode,
64 io_mode,
65 rom_mode
66 } flash_mode_t;
68 struct pflash_t {
69 MemoryRegion mem;
70 BlockDriverState *bs;
71 hwaddr base;
72 uint32_t sector_len;
73 uint32_t total_len;
74 int width;
75 int wcycle; /* if 0, the flash is read normally */
76 flash_mode_t mode;
77 int bypass;
78 int ro;
79 uint8_t cmd;
80 uint8_t status;
81 uint16_t ident[4];
82 uint8_t cfi_table[0x52];
83 QEMUTimer *timer;
84 void *storage;
87 static void pflash_io_mode(pflash_t *pfl)
89 if (pfl->mode != io_mode) {
90 DPRINTF("switch to i/o mode\n");
91 memory_region_rom_device_set_readable(&pfl->mem, false);
92 //~ DPRINTF("0x%08x 0x%08x\n", pfl->base, pfl->total_len);
93 pfl->mode = io_mode;
97 static void pflash_rom_mode(pflash_t *pfl)
99 if (pfl->mode != rom_mode) {
100 DPRINTF("switch to rom mode\n");
101 memory_region_rom_device_set_readable(&pfl->mem, true);
102 pfl->mode = rom_mode;
106 static void pflash_timer (void *opaque)
108 pflash_t *pfl = opaque;
110 DPRINTF("command %02x done\n", pfl->cmd);
111 /* Reset flash */
112 pfl->status ^= 0x80;
113 if (pfl->bypass) {
114 pfl->wcycle = 2;
115 } else {
116 pflash_rom_mode(pfl);
117 pfl->wcycle = 0;
119 //~ check!!!
120 pfl->cmd = 0;
123 static uint32_t pflash_read (pflash_t *pfl, uint32_t offset, int width)
125 uint32_t boff;
126 uint32_t ret;
127 uint8_t *p;
129 ret = -1;
130 offset -= pfl->base;
131 DPRINTF("offset %08x\n", offset);
132 boff = offset & 0xFF;
133 if (pfl->width == 2)
134 boff = boff >> 1;
135 else if (pfl->width == 4)
136 boff = boff >> 2;
137 switch (pfl->cmd) {
138 default:
139 /* This should never happen : reset state & treat it as a read*/
140 DPRINTF("unknown command state: %x\n", pfl->cmd);
141 pfl->wcycle = 0;
142 pfl->cmd = 0;
143 case 0x80:
144 /* We accept reads during second unlock sequence... */
145 case 0x00:
146 flash_read:
147 /* Flash area read */
148 p = pfl->storage;
149 switch (width) {
150 case 1:
151 ret = p[offset];
152 // DPRINTF("data offset %08x %02x\n", offset, ret);
153 break;
154 case 2:
155 #if defined(TARGET_WORDS_BIGENDIAN)
156 ret = p[offset] << 8;
157 ret |= p[offset + 1];
158 #else
159 ret = p[offset];
160 ret |= p[offset + 1] << 8;
161 #endif
162 // DPRINTF("data offset %08x %04x\n", offset, ret);
163 break;
164 case 4:
165 #if defined(TARGET_WORDS_BIGENDIAN)
166 ret = p[offset] << 24;
167 ret |= p[offset + 1] << 16;
168 ret |= p[offset + 2] << 8;
169 ret |= p[offset + 3];
170 #else
171 ret = p[offset];
172 ret |= p[offset + 1] << 8;
173 ret |= p[offset + 2] << 16;
174 ret |= p[offset + 3] << 24;
175 #endif
176 // DPRINTF("data offset %08x %08x\n", offset, ret);
177 break;
179 break;
180 case 0x90:
181 /* flash ID read */
182 switch (boff) {
183 case 0x00:
184 case 0x01:
185 ret = pfl->ident[boff & 0x01];
186 break;
187 case 0x02:
188 ret = 0x00; /* Pretend all sectors are unprotected */
189 break;
190 case 0x0E:
191 case 0x0F:
192 if (pfl->ident[2 + (boff & 0x01)] == (uint8_t)-1)
193 goto flash_read;
194 ret = pfl->ident[2 + (boff & 0x01)];
195 break;
196 default:
197 goto flash_read;
199 DPRINTF("ID %d %x\n", boff, ret);
200 break;
201 case 0xA0:
202 case 0x10:
203 case 0x30:
204 /* Status register read */
205 ret = pfl->status;
206 DPRINTF("status %x\n", ret);
207 /* Toggle bit 6 */
208 pfl->status ^= 0x40;
209 break;
210 case 0x98:
211 /* CFI query mode */
212 if (boff < sizeof(pfl->cfi_table)) {
213 ret = pfl->cfi_table[boff];
214 } else {
215 ret = 0;
217 break;
220 DPRINTF("offset %08x %08x %d\n", offset, ret, width);
221 return ret;
224 /* update flash content on disk */
225 static void pflash_update(pflash_t *pfl, int offset,
226 int size)
228 int offset_end;
229 if (pfl->bs) {
230 offset_end = offset + size;
231 /* round to sectors */
232 offset = offset >> 9;
233 offset_end = (offset_end + 511) >> 9;
234 bdrv_write(pfl->bs, offset, pfl->storage + (offset << 9),
235 offset_end - offset);
239 static void pflash_write(pflash_t *pfl, uint32_t offset, uint32_t value,
240 int width, bool be)
242 uint32_t boff;
243 uint8_t *p;
244 uint8_t cmd = value;
245 uint32_t sector_len = pfl->sector_len;
247 /* WARNING: when the memory area is in ROMD mode, the offset is a
248 ram offset, not a physical address */
249 if (pfl->mode == rom_mode) {
250 // TODO: next line raises a compiler warning, needs fix.
251 //~ offset -= (uint32_t)pfl->storage;
252 assert(0);
253 } else {
254 offset -= pfl->base;
257 DPRINTF("offset %08x %08x %d\n", offset, value, width);
258 if (pfl->cmd != 0xA0 && cmd == 0xf0) {
259 DPRINTF("flash reset asked (%02x %02x)\n", pfl->cmd, cmd);
260 goto reset_flash;
262 if (pfl->cmd != 0xA0 && cmd == 0xff) {
263 /* Intel command (read array mode). */
264 DPRINTF("read array asked (%02x %02x)\n", pfl->cmd, cmd);
265 goto reset_flash;
267 //~ !!! next code only for certain flash chips
268 if (offset < 0x004000) {
269 sector_len = 0x4000;
270 } else if (offset < 0x008000) {
271 sector_len = 0x2000;
272 } else if (offset < 0x010000) {
273 sector_len = 0x8000;
275 boff = offset & (sector_len - 1);
276 if (pfl->width == 2)
277 boff = boff >> 1;
278 else if (pfl->width == 4)
279 boff = boff >> 2;
280 switch (pfl->wcycle) {
281 case 0:
282 /* We're in read mode */
283 if (boff == 0x55 && cmd == 0x98) {
284 enter_CFI_mode:
285 /* Enter CFI query mode */
286 pfl->wcycle = 7;
287 pfl->cmd = 0x98;
288 /* Set the device in I/O access mode */
289 pflash_io_mode(pfl);
290 return;
292 check_unlock0:
293 if ((boff != 0x555 && offset != 0xaaaa) || cmd != 0xAA) {
294 DPRINTF("unlock0 failed %04x %02x %04x\n", boff, cmd, 0x555);
295 goto reset_flash;
297 DPRINTF("unlock sequence started\n");
298 /* Set the device in I/O access mode */
299 pflash_io_mode(pfl);
300 break;
301 case 1:
302 /* We started an unlock sequence */
303 check_unlock1:
304 if ((boff != 0x2AA && offset != 0x5554) || cmd != 0x55) {
305 DPRINTF("unlock1 failed %04x %02x\n", boff, cmd);
306 goto reset_flash;
308 DPRINTF("unlock sequence done\n");
309 break;
310 case 2:
311 /* We finished an unlock sequence */
312 if (!pfl->bypass && boff != 0x555 && offset != 0xaaaa) {
313 DPRINTF("command failed %04x %02x\n", boff, cmd);
314 goto reset_flash;
316 switch (cmd) {
317 case 0x20:
318 pfl->bypass = 1;
319 goto do_bypass;
320 case 0x80:
321 case 0x90:
322 case 0xA0:
323 pfl->cmd = cmd;
324 DPRINTF("starting command %02x\n", cmd);
325 break;
326 default:
327 DPRINTF("unknown command %02x\n", cmd);
328 goto reset_flash;
330 break;
331 case 3:
332 switch (pfl->cmd) {
333 case 0x80:
334 /* We need another unlock sequence */
335 goto check_unlock0;
336 case 0xA0:
337 DPRINTF("write data offset %08x %08x %d\n", offset, value, width);
338 p = pfl->storage;
339 switch (width) {
340 case 1:
341 p[offset] &= value;
342 pflash_update(pfl, offset, 1);
343 break;
344 case 2:
345 #if defined(TARGET_WORDS_BIGENDIAN)
346 p[offset] &= value >> 8;
347 p[offset + 1] &= value;
348 #else
349 p[offset] &= value;
350 p[offset + 1] &= value >> 8;
351 #endif
352 pflash_update(pfl, offset, 2);
353 break;
354 case 4:
355 #if defined(TARGET_WORDS_BIGENDIAN)
356 p[offset] &= value >> 24;
357 p[offset + 1] &= value >> 16;
358 p[offset + 2] &= value >> 8;
359 p[offset + 3] &= value;
360 #else
361 p[offset] &= value;
362 p[offset + 1] &= value >> 8;
363 p[offset + 2] &= value >> 16;
364 p[offset + 3] &= value >> 24;
365 #endif
366 pflash_update(pfl, offset, 4);
367 break;
369 pfl->status = 0x00 | ~(value & 0x80);
370 /* Let's pretend write is immediate */
371 if (pfl->bypass)
372 goto do_bypass;
373 goto reset_flash;
374 case 0x90:
375 if (pfl->bypass && cmd == 0x00) {
376 /* Unlock bypass reset */
377 goto reset_flash;
379 /* We can enter CFI query mode from autoselect mode */
380 if (boff == 0x55 && cmd == 0x98)
381 goto enter_CFI_mode;
382 /* No break here */
383 default:
384 DPRINTF("invalid write for command %02x\n", pfl->cmd);
385 goto reset_flash;
387 case 4:
388 switch (pfl->cmd) {
389 case 0xA0:
390 /* Ignore writes while flash data write is occurring */
391 /* As we suppose write is immediate, this should never happen */
392 return;
393 case 0x80:
394 goto check_unlock1;
395 default:
396 /* Should never happen */
397 DPRINTF("invalid command state %02x (wc 4)\n", pfl->cmd);
398 goto reset_flash;
400 break;
401 case 5:
402 switch (cmd) {
403 case 0x10:
404 if (boff != 0x555) {
405 DPRINTF("chip erase: invalid address %04x\n", offset);
406 goto reset_flash;
408 /* Chip erase */
409 DPRINTF("start chip erase\n");
410 memset(pfl->storage, 0xFF, pfl->total_len);
411 pfl->status = 0x00;
412 pflash_update(pfl, 0, pfl->total_len);
413 /* Let's wait 5 seconds before chip erase is done */
414 timer_mod(pfl->timer,
415 qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + (NANOSECONDS_PER_SECOND * 5));
416 break;
417 case 0x30:
418 /* Sector erase */
419 p = pfl->storage;
420 offset &= ~(sector_len - 1);
421 DPRINTF("start sector erase at %08x\n", offset);
422 memset(p + offset, 0xFF, sector_len);
423 pflash_update(pfl, offset, sector_len);
424 pfl->status = 0x00;
425 /* Let's wait 1/2 second before sector erase is done */
426 timer_mod(pfl->timer,
427 qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + (NANOSECONDS_PER_SECOND / 2));
428 break;
429 default:
430 DPRINTF("invalid command %02x (wc 5)\n", cmd);
431 goto reset_flash;
433 pfl->cmd = cmd;
434 break;
435 case 6:
436 switch (pfl->cmd) {
437 case 0x10:
438 /* Ignore writes during chip erase */
439 return;
440 case 0x30:
441 /* Ignore writes during sector erase */
442 return;
443 default:
444 /* Should never happen */
445 DPRINTF("invalid command state %02x (wc 6)\n", pfl->cmd);
446 goto reset_flash;
448 break;
449 case 7: /* Special value for CFI queries */
450 DPRINTF("invalid write in CFI query mode\n");
451 goto reset_flash;
452 default:
453 /* Should never happen */
454 DPRINTF("invalid write state (wc 7)\n");
455 goto reset_flash;
457 pfl->wcycle++;
459 return;
461 /* Reset flash */
462 reset_flash:
463 pflash_rom_mode(pfl);
464 pfl->bypass = 0;
465 pfl->wcycle = 0;
466 pfl->cmd = 0;
467 return;
469 do_bypass:
470 pfl->wcycle = 2;
471 pfl->cmd = 0;
472 return;
476 static uint32_t pflash_readb_be(void *opaque, hwaddr addr)
478 return pflash_read(opaque, addr, 1);
481 static uint32_t pflash_readw_be(void *opaque, hwaddr addr)
483 pflash_t *pfl = opaque;
485 return pflash_read(pfl, addr, 2);
488 static uint32_t pflash_readl_be(void *opaque, hwaddr addr)
490 pflash_t *pfl = opaque;
492 return pflash_read(pfl, addr, 4);
495 static void pflash_writeb_be(void *opaque, hwaddr addr,
496 uint32_t value)
498 pflash_write(opaque, addr, value, 1, true);
501 static void pflash_writew_be(void *opaque, hwaddr addr,
502 uint32_t value)
504 pflash_t *pfl = opaque;
506 pflash_write(pfl, addr, value, 2, true);
509 static void pflash_writel_be(void *opaque, hwaddr addr,
510 uint32_t value)
512 pflash_t *pfl = opaque;
514 pflash_write(pfl, addr, value, 4, true);
517 static const MemoryRegionOps pflash_cfi01_ops_be = {
518 .old_mmio = {
519 .read = { pflash_readb_be, pflash_readw_be, pflash_readl_be, },
520 .write = { pflash_writeb_be, pflash_writew_be, pflash_writel_be, },
522 .endianness = DEVICE_NATIVE_ENDIAN,
525 /* Count trailing zeroes of a 32 bits quantity */
526 static int ctz32 (uint32_t n)
528 int ret;
530 ret = 0;
531 if (!(n & 0xFFFF)) {
532 ret += 16;
533 n = n >> 16;
535 if (!(n & 0xFF)) {
536 ret += 8;
537 n = n >> 8;
539 if (!(n & 0xF)) {
540 ret += 4;
541 n = n >> 4;
543 if (!(n & 0x3)) {
544 ret += 2;
545 n = n >> 2;
547 if (!(n & 0x1)) {
548 ret++;
549 n = n >> 1;
551 #if 0 /* This is not necessary as n is never 0 */
552 if (!n)
553 ret++;
554 #endif
556 return ret;
559 static void flash_reset(void *opaque)
561 pflash_t *pfl = (pflash_t *)opaque;
562 DPRINTF("%s:%u\n", __FILE__, __LINE__);
563 pflash_rom_mode(pfl);
564 pfl->bypass = 0;
565 pfl->wcycle = 0;
566 pfl->cmd = 0;
569 pflash_t *pflash_amd_register (hwaddr base, ram_addr_t off,
570 BlockDriverState *bs,
571 uint32_t sector_len, int nb_blocs, int width,
572 uint16_t id0, uint16_t id1,
573 uint16_t id2, uint16_t id3)
575 pflash_t *pfl;
576 target_long total_len;
578 #ifdef PFLASH_DEBUG
579 if (getenv("DEBUG_FLASH")) {
580 traceflag = strtoul(getenv("DEBUG_FLASH"), 0, 0);
582 DPRINTF("Logging enabled for FLASH in %s\n", __func__);
583 #endif
585 total_len = sector_len * nb_blocs;
587 DPRINTF("flash size " TARGET_FMT_lu " MiB (" TARGET_FMT_lu " x %u bytes)\n",
588 total_len / MiB, total_len / width, width);
590 /* XXX: to be fixed */
591 if (total_len != (2 * MiB) && total_len != (4 * MiB) &&
592 total_len != (8 * MiB) && total_len != (16 * MiB) &&
593 total_len != (32 * MiB) && total_len != (64 * MiB))
594 return NULL;
596 pfl = g_new0(pflash_t, 1);
598 memory_region_init_rom_device(
599 &pfl->mem, be ? &pflash_cfi01_ops_be : &pflash_cfi01_ops_le, pfl,
600 qdev, name, size);
601 pfl->storage = memory_region_get_ram_ptr(&pfl->mem);
602 memory_region_add_subregion(get_system_memory(), base, &pfl->mem);
604 pfl->base = base;
605 pfl->sector_len = sector_len;
606 pfl->total_len = total_len;
607 pflash_rom_mode(pfl);
608 pfl->bs = bs;
609 if (pfl->bs) {
610 /* read the initial flash content */
611 bdrv_read(pfl->bs, 0, pfl->storage, total_len >> 9);
612 if (ret < 0) {
613 memory_region_del_subregion(get_system_memory(), &pfl->mem);
614 memory_region_destroy(&pfl->mem);
615 g_free(pfl);
616 return NULL;
619 #if 0 /* XXX: there should be a bit to set up read-only,
620 * the same way the hardware does (with WP pin).
622 pfl->ro = 1;
623 #else
624 pfl->ro = 0;
625 #endif
626 pfl->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, pflash_timer, pfl);
627 pfl->width = width;
628 pfl->wcycle = 0;
629 pfl->cmd = 0;
630 pfl->status = 0;
631 pfl->ident[0] = id0;
632 pfl->ident[1] = id1;
633 pfl->ident[2] = id2;
634 pfl->ident[3] = id3;
635 #if 0
636 /* Hardcoded CFI table (mostly from SG29 Spansion flash) */
637 /* Standard "QRY" string */
638 pfl->cfi_table[0x10] = 'Q';
639 pfl->cfi_table[0x11] = 'R';
640 pfl->cfi_table[0x12] = 'Y';
641 /* Command set (AMD/Fujitsu) */
642 pfl->cfi_table[0x13] = P_ID_AMD_STD;
643 pfl->cfi_table[0x14] = 0x00;
644 /* Primary extended table address (none) */
645 pfl->cfi_table[0x15] = 0x00;
646 pfl->cfi_table[0x16] = 0x00;
647 /* Alternate command set (none) */
648 pfl->cfi_table[0x17] = 0x00;
649 pfl->cfi_table[0x18] = 0x00;
650 /* Alternate extended table (none) */
651 pfl->cfi_table[0x19] = 0x00;
652 pfl->cfi_table[0x1A] = 0x00;
653 /* Vcc min */
654 pfl->cfi_table[0x1B] = 0x27;
655 /* Vcc max */
656 pfl->cfi_table[0x1C] = 0x36;
657 /* Vpp min (no Vpp pin) */
658 pfl->cfi_table[0x1D] = 0x00;
659 /* Vpp max (no Vpp pin) */
660 pfl->cfi_table[0x1E] = 0x00;
661 /* Reserved */
662 pfl->cfi_table[0x1F] = 0x07;
663 /* Timeout for min size buffer write (16 µs) */
664 pfl->cfi_table[0x20] = 0x04;
665 /* Typical timeout for block erase (512 ms) */
666 pfl->cfi_table[0x21] = 0x09;
667 /* Typical timeout for full chip erase (4096 ms) */
668 pfl->cfi_table[0x22] = 0x0C;
669 /* Reserved */
670 pfl->cfi_table[0x23] = 0x01;
671 /* Max timeout for buffer write */
672 pfl->cfi_table[0x24] = 0x04;
673 /* Max timeout for block erase */
674 pfl->cfi_table[0x25] = 0x0A;
675 /* Max timeout for chip erase */
676 pfl->cfi_table[0x26] = 0x0D;
677 /* Device size */
678 //~ pfl->cfi_table[0x27] = ctz32(total_len) + 1;
679 pfl->cfi_table[0x27] = ctz32(total_len); // !!! 0x15
680 /* Flash device interface (8 & 16 bits) */
681 pfl->cfi_table[0x28] = 0x02;
682 pfl->cfi_table[0x29] = 0x00;
683 /* Max number of bytes in multi-bytes write */
684 pfl->cfi_table[0x2A] = 0x05;
685 pfl->cfi_table[0x2B] = 0x00;
686 /* Number of erase block regions (uniform) */
687 pfl->cfi_table[0x2C] = 0x01;
688 /* Erase block region 1 */
689 pfl->cfi_table[0x2D] = nb_blocs - 1;
690 pfl->cfi_table[0x2E] = (nb_blocs - 1) >> 8;
691 pfl->cfi_table[0x2F] = sector_len >> 8;
692 pfl->cfi_table[0x30] = sector_len >> 16;
693 #endif
695 if (0) {
696 } else if ((id0 == MANUFACTURER_AMD && id1 == AM29LV160DB) ||
697 (id0 == MANUFACTURER_004A && id1 == ES29LV160DB) ||
698 (id0 == MANUFACTURER_SPANSION && id1 == S29AL016DB)) {
699 static const uint8_t data[] = {
700 /* 0x10 */ 'Q', 'R', 'Y', 0x02, 0x00, 0x40, 0x00, 0x00,
701 /* 0x18 */ 0x00, 0x00, 0x00, 0x27, 0x36, 0x00, 0x00, 0x04,
702 /* 0x20 */ 0x00, 0x0a, 0x00, 0x05, 0x00, 0x04, 0x00, 0x15,
703 /* 0x28 */ 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x40,
704 /* 0x30 */ 0x00, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x80,
705 /* 0x38 */ 0x00, 0x1e, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
706 /* 0x40 */ 'P', 'R', 'I', '1', '0', 0x00, 0x02, 0x01,
707 /* 0x48 */ 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
709 memcpy(&pfl->cfi_table[0x10], data, sizeof(data));
710 //~ pfl->cfi_table[0x39] = nb_blocs - 2; // 0x1e
711 //~ pfl->cfi_table[0x3a] = (nb_blocs - 2) >> 8; // 0x00
712 //~ pfl->cfi_table[0x3b] = (sector_len / 256); // 0x01
713 //~ pfl->cfi_table[0x3c] = (sector_len / 256) >> 8; // 0x00
714 } else if (id0 == MANUFACTURER_MACRONIX && (id1 == MX29LV320CB ||
715 id1 == MX29LV320CT || id1 == MX29LV640BB || id1 == MX29LV640BT)) {
716 static const uint8_t data[] = {
717 /* 0x10 */ 'Q', 'R', 'Y', 0x02, 0x00, 0x40, 0x00, 0x00,
718 /* 0x18 */ 0x00, 0x00, 0x00, 0x27, 0x36, 0x00, 0x00, 0x04,
719 /* 0x20 */ 0x00, 0x0a, 0x00, 0x05, 0x00, 0x04, 0x00, 0x16,
720 /* 0x28 */ 0x02, 0x00, 0x00, 0x00, 0x02, 0x07, 0x00, 0x20,
721 /* 0x30 */ 0x00, 0x3e, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
722 /* 0x38 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
723 /* 0x40 */ 'P', 'R', 'I', '1', '1', 0x00, 0x02, 0x04,
724 /* 0x48 */ 0x01, 0x04, 0x00, 0x00, 0x00, 0xb5, 0xc5, 0x02,
726 memcpy(&pfl->cfi_table[0x10], data, sizeof(data));
727 if (id1 == MX29LV640BB || id1 == MX29LV640BT) {
728 pfl->cfi_table[0x27] = 0x17;
729 pfl->cfi_table[0x31] = 0x7e;
731 if (id1 == MX29LV320CT || id1 == MX29LV640BT) {
732 pfl->cfi_table[0x4f] = 0x03;
734 } else {
735 /* SG29 Spansion flash */
736 static const uint8_t data[] = {
737 /* 0x10 */ 'Q', 'R', 'Y', 0x02, 0x00, 0x00, 0x00, 0x00,
738 /* 0x18 */ 0x00, 0x00, 0x00, 0x27, 0x36, 0x00, 0x00, 0x07,
739 /* 0x20 */ 0x04, 0x09, 0x0c, 0x01, 0x04, 0x0a, 0x0d, 0x16,
740 /* 0x28 */ 0x02, 0x00, 0x05, 0x00, 0x01, 0x00, 0x00, 0x40,
742 memcpy(&pfl->cfi_table[0x10], data, sizeof(data));
743 pfl->cfi_table[0x27] = ctz32(total_len);
744 pfl->cfi_table[0x2D] = nb_blocs - 1;
745 pfl->cfi_table[0x2E] = (nb_blocs - 1) >> 8;
746 pfl->cfi_table[0x2F] = sector_len >> 8;
747 pfl->cfi_table[0x30] = sector_len >> 16;
750 qemu_register_reset(flash_reset, pfl);
752 return pfl;
755 #if 0 // TODO
756 MemoryRegion *pflash_amd_get_memory(pflash_t *fl)
758 return &fl->mem;
760 #endif