Revision cfe5f011 hw/pflash_cfi02.c
b/hw/pflash_cfi02.c | ||
---|---|---|
39 | 39 |
#include "flash.h" |
40 | 40 |
#include "qemu-timer.h" |
41 | 41 |
#include "block.h" |
42 |
#include "exec-memory.h" |
|
42 | 43 |
|
43 | 44 |
//#define PFLASH_DEBUG |
44 | 45 |
#ifdef PFLASH_DEBUG |
... | ... | |
69 | 70 |
uint8_t cfi_len; |
70 | 71 |
uint8_t cfi_table[0x52]; |
71 | 72 |
QEMUTimer *timer; |
72 |
ram_addr_t off; |
|
73 |
int fl_mem; |
|
73 |
/* The device replicates the flash memory across its memory space. Emulate |
|
74 |
* that by having a container (.mem) filled with an array of aliases |
|
75 |
* (.mem_mappings) pointing to the flash memory (.orig_mem). |
|
76 |
*/ |
|
77 |
MemoryRegion mem; |
|
78 |
MemoryRegion *mem_mappings; /* array; one per mapping */ |
|
79 |
MemoryRegion orig_mem; |
|
74 | 80 |
int rom_mode; |
75 | 81 |
int read_counter; /* used for lazy switch-back to rom mode */ |
76 | 82 |
void *storage; |
77 | 83 |
}; |
78 | 84 |
|
79 |
static void pflash_register_memory(pflash_t *pfl, int rom_mode) |
|
85 |
/* |
|
86 |
* Set up replicated mappings of the same region. |
|
87 |
*/ |
|
88 |
static void pflash_setup_mappings(pflash_t *pfl) |
|
80 | 89 |
{ |
81 |
unsigned long phys_offset = pfl->fl_mem; |
|
82 |
int i; |
|
83 |
|
|
84 |
if (rom_mode) |
|
85 |
phys_offset |= pfl->off | IO_MEM_ROMD; |
|
86 |
pfl->rom_mode = rom_mode; |
|
90 |
unsigned i; |
|
91 |
target_phys_addr_t size = memory_region_size(&pfl->orig_mem); |
|
92 |
|
|
93 |
memory_region_init(&pfl->mem, "pflash", pfl->mappings * size); |
|
94 |
pfl->mem_mappings = g_new(MemoryRegion, pfl->mappings); |
|
95 |
for (i = 0; i < pfl->mappings; ++i) { |
|
96 |
memory_region_init_alias(&pfl->mem_mappings[i], "pflash-alias", |
|
97 |
&pfl->orig_mem, 0, size); |
|
98 |
memory_region_add_subregion(&pfl->mem, i * size, &pfl->mem_mappings[i]); |
|
99 |
} |
|
100 |
} |
|
87 | 101 |
|
88 |
for (i = 0; i < pfl->mappings; i++)
|
|
89 |
cpu_register_physical_memory(pfl->base + i * pfl->chip_len,
|
|
90 |
pfl->chip_len, phys_offset);
|
|
102 |
static void pflash_register_memory(pflash_t *pfl, int rom_mode)
|
|
103 |
{
|
|
104 |
memory_region_rom_device_set_readable(&pfl->orig_mem, rom_mode);
|
|
91 | 105 |
} |
92 | 106 |
|
93 | 107 |
static void pflash_timer (void *opaque) |
... | ... | |
538 | 552 |
pflash_write(pfl, addr, value, 4, 0); |
539 | 553 |
} |
540 | 554 |
|
541 |
static CPUWriteMemoryFunc * const pflash_write_ops_be[] = { |
|
542 |
&pflash_writeb_be, |
|
543 |
&pflash_writew_be, |
|
544 |
&pflash_writel_be, |
|
545 |
}; |
|
546 |
|
|
547 |
static CPUReadMemoryFunc * const pflash_read_ops_be[] = { |
|
548 |
&pflash_readb_be, |
|
549 |
&pflash_readw_be, |
|
550 |
&pflash_readl_be, |
|
555 |
static const MemoryRegionOps pflash_cfi02_ops_be = { |
|
556 |
.old_mmio = { |
|
557 |
.read = { pflash_readb_be, pflash_readw_be, pflash_readl_be, }, |
|
558 |
.write = { pflash_writeb_be, pflash_writew_be, pflash_writel_be, }, |
|
559 |
}, |
|
560 |
.endianness = DEVICE_NATIVE_ENDIAN, |
|
551 | 561 |
}; |
552 | 562 |
|
553 |
static CPUWriteMemoryFunc * const pflash_write_ops_le[] = { |
|
554 |
&pflash_writeb_le, |
|
555 |
&pflash_writew_le, |
|
556 |
&pflash_writel_le, |
|
557 |
}; |
|
558 |
|
|
559 |
static CPUReadMemoryFunc * const pflash_read_ops_le[] = { |
|
560 |
&pflash_readb_le, |
|
561 |
&pflash_readw_le, |
|
562 |
&pflash_readl_le, |
|
563 |
static const MemoryRegionOps pflash_cfi02_ops_le = { |
|
564 |
.old_mmio = { |
|
565 |
.read = { pflash_readb_le, pflash_readw_le, pflash_readl_le, }, |
|
566 |
.write = { pflash_writeb_le, pflash_writew_le, pflash_writel_le, }, |
|
567 |
}, |
|
568 |
.endianness = DEVICE_NATIVE_ENDIAN, |
|
563 | 569 |
}; |
564 | 570 |
|
565 | 571 |
/* Count trailing zeroes of a 32 bits quantity */ |
... | ... | |
598 | 604 |
return ret; |
599 | 605 |
} |
600 | 606 |
|
601 |
pflash_t *pflash_cfi02_register(target_phys_addr_t base, ram_addr_t off, |
|
607 |
pflash_t *pflash_cfi02_register(target_phys_addr_t base, |
|
608 |
DeviceState *qdev, const char *name, |
|
609 |
target_phys_addr_t size, |
|
602 | 610 |
BlockDriverState *bs, uint32_t sector_len, |
603 | 611 |
int nb_blocs, int nb_mappings, int width, |
604 | 612 |
uint16_t id0, uint16_t id1, |
... | ... | |
618 | 626 |
return NULL; |
619 | 627 |
#endif |
620 | 628 |
pfl = g_malloc0(sizeof(pflash_t)); |
621 |
/* FIXME: Allocate ram ourselves. */ |
|
622 |
pfl->storage = qemu_get_ram_ptr(off); |
|
623 |
if (be) { |
|
624 |
pfl->fl_mem = cpu_register_io_memory(pflash_read_ops_be, |
|
625 |
pflash_write_ops_be, |
|
626 |
pfl, DEVICE_NATIVE_ENDIAN); |
|
627 |
} else { |
|
628 |
pfl->fl_mem = cpu_register_io_memory(pflash_read_ops_le, |
|
629 |
pflash_write_ops_le, |
|
630 |
pfl, DEVICE_NATIVE_ENDIAN); |
|
631 |
} |
|
632 |
pfl->off = off; |
|
629 |
memory_region_init_rom_device( |
|
630 |
&pfl->orig_mem, be ? &pflash_cfi02_ops_be : &pflash_cfi02_ops_le, pfl, |
|
631 |
qdev, name, size); |
|
632 |
pfl->storage = memory_region_get_ram_ptr(&pfl->orig_mem); |
|
633 | 633 |
pfl->base = base; |
634 | 634 |
pfl->chip_len = chip_len; |
635 | 635 |
pfl->mappings = nb_mappings; |
636 |
pflash_register_memory(pfl, 1); |
|
637 | 636 |
pfl->bs = bs; |
638 | 637 |
if (pfl->bs) { |
639 | 638 |
/* read the initial flash content */ |
640 | 639 |
ret = bdrv_read(pfl->bs, 0, pfl->storage, chip_len >> 9); |
641 | 640 |
if (ret < 0) { |
642 |
cpu_unregister_io_memory(pfl->fl_mem); |
|
643 | 641 |
g_free(pfl); |
644 | 642 |
return NULL; |
645 | 643 |
} |
646 | 644 |
} |
645 |
pflash_setup_mappings(pfl); |
|
646 |
pfl->rom_mode = 1; |
|
647 |
memory_region_add_subregion(get_system_memory(), pfl->base, &pfl->mem); |
|
647 | 648 |
#if 0 /* XXX: there should be a bit to set up read-only, |
648 | 649 |
* the same way the hardware does (with WP pin). |
649 | 650 |
*/ |
Also available in: Unified diff