cc32rs512: add simulation of the built-in flash controller
This commit is contained in:
parent
a4fb8f496a
commit
0aafdf2366
220
hw/cc32rs512.c
220
hw/cc32rs512.c
|
@ -23,6 +23,201 @@
|
|||
#include "boards.h"
|
||||
#include "exec-memory.h"
|
||||
|
||||
/***********************************************************************
|
||||
* Flash controller
|
||||
***********************************************************************/
|
||||
|
||||
enum cc32_flcon_reg {
|
||||
FLCON = 0x00,
|
||||
FLSDP1 = 0x04,
|
||||
FLSDP2 = 0x08,
|
||||
FLSTS = 0x0C,
|
||||
FLBUF = 0x10,
|
||||
};
|
||||
|
||||
#define NUM_FL_REGS ((FLBUF>>2) + 4)
|
||||
|
||||
enum write_state {
|
||||
WRST_NONE,
|
||||
WRST_SDP1_55,
|
||||
WRST_SDP1_AA,
|
||||
WRST_ERASE,
|
||||
WRST_PROGRAM,
|
||||
};
|
||||
|
||||
typedef struct cc32_flcon_state {
|
||||
SysBusDevice busdev;
|
||||
MemoryRegion iomem;
|
||||
qemu_irq irq;
|
||||
|
||||
uint32_t regs[NUM_FL_REGS];
|
||||
enum write_state wrst;
|
||||
uint8_t *storage;
|
||||
uint8_t *ram_storage;
|
||||
} cc32_flcon_state;
|
||||
|
||||
static void cc32_flcon_update(cc32_flcon_state *s)
|
||||
{
|
||||
if (s->regs[FLSTS>>2] & 1)
|
||||
qemu_set_irq(s->irq, 1);
|
||||
else
|
||||
qemu_set_irq(s->irq, 0);
|
||||
}
|
||||
|
||||
static uint64_t cc32_flcon_read(void *opaque, target_phys_addr_t offset,
|
||||
unsigned size)
|
||||
{
|
||||
cc32_flcon_state *s = (cc32_flcon_state *)opaque;
|
||||
|
||||
return s->regs[offset>>2];
|
||||
}
|
||||
|
||||
static void cc32_flcon_write(void *opaque, target_phys_addr_t offset,
|
||||
uint64_t value, unsigned size)
|
||||
{
|
||||
cc32_flcon_state *s = (cc32_flcon_state *)opaque;
|
||||
|
||||
s->regs[offset>>2] = value;
|
||||
|
||||
switch (offset) {
|
||||
case FLSDP1:
|
||||
switch (value) {
|
||||
case 0x55:
|
||||
s->wrst = WRST_SDP1_55;
|
||||
break;
|
||||
case 0xAA:
|
||||
s->wrst = WRST_SDP1_AA;
|
||||
break;
|
||||
default:
|
||||
/* Signal incorrect operation */
|
||||
s->regs[FLSTS>>2] |= (1 << 1);
|
||||
s->wrst = WRST_NONE;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case FLSDP2:
|
||||
if (s->wrst == WRST_SDP1_55 && (value == 0xAA)) {
|
||||
s->wrst = WRST_ERASE;
|
||||
/* actual ERASE will be performed once the program
|
||||
* writes a 0xFF to any address within the flash page */
|
||||
} else if ((s->wrst == WRST_SDP1_AA) && (value == 0x55)) {
|
||||
s->wrst = WRST_PROGRAM;
|
||||
/* actual PROGRAM will be performed once the program
|
||||
* writes a 0x00 to any address within the flash page */
|
||||
} else {
|
||||
/* Signal incorrect operation */
|
||||
s->regs[FLSTS>>2] |= (1 << 1);
|
||||
s->wrst = WRST_NONE;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case FLSTS:
|
||||
/* clear bits */
|
||||
s->regs[offset>>2] &= ~(value & 3);
|
||||
break;
|
||||
}
|
||||
|
||||
cc32_flcon_update(s);
|
||||
}
|
||||
|
||||
/* callback for user writes to the flash memory region */
|
||||
static void cc32_flash_write(void *opaque, target_phys_addr_t offset,
|
||||
uint64_t value, unsigned size)
|
||||
{
|
||||
cc32_flcon_state *s = (cc32_flcon_state *)opaque;
|
||||
uint32_t epsize = (s->regs[FLCON>>2] >> 3);
|
||||
uint32_t page_size, mask;
|
||||
|
||||
if (epsize == 0) {
|
||||
page_size = 512;
|
||||
mask = 0xfffffe00;
|
||||
} else {
|
||||
page_size = 256;
|
||||
mask = 0xffffff00;
|
||||
}
|
||||
/* FIXME: check for 0x00 / 0xFF as value */
|
||||
|
||||
switch (s->wrst) {
|
||||
case WRST_ERASE:
|
||||
fprintf(stderr, "cc32-flcon: Erasing %u at offset 0x%06x\n",
|
||||
page_size, offset & mask);
|
||||
memset(s->storage + (offset & mask), 0xFF, page_size);
|
||||
s->regs[FLSTS>>2] |= 1;
|
||||
s->wrst = WRST_NONE;
|
||||
break;
|
||||
case WRST_PROGRAM:
|
||||
fprintf(stderr, "cc32-flcon: Programming %u at offset 0x%06x\n",
|
||||
page_size, offset & mask);
|
||||
memcpy(s->storage + (offset & mask),
|
||||
s->ram_storage + ((s->regs[FLBUF>>2] & 0xffffff) - 0xC0000),
|
||||
page_size);
|
||||
s->regs[FLSTS>>2] |= 1;
|
||||
s->wrst = WRST_NONE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
cc32_flcon_update(s);
|
||||
}
|
||||
|
||||
|
||||
/* MMIO interface of the FLCON */
|
||||
static const MemoryRegionOps cc32_flcon_ops = {
|
||||
.read = cc32_flcon_read,
|
||||
.write = cc32_flcon_write,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
.valid = {
|
||||
.min_access_size = 4,
|
||||
.max_access_size = 4,
|
||||
},
|
||||
};
|
||||
|
||||
/* Flash memory writes for memory_region_init_rom_device() */
|
||||
static const MemoryRegionOps cc32_flash_ops = {
|
||||
.write = cc32_flash_write,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
};
|
||||
|
||||
static int cc32_flcon_init(SysBusDevice *dev)
|
||||
{
|
||||
cc32_flcon_state *s = FROM_SYSBUS(cc32_flcon_state, dev);
|
||||
|
||||
sysbus_init_irq(dev, &s->irq);
|
||||
|
||||
memory_region_init_io(&s->iomem, &cc32_flcon_ops, s, "cc32-flcon", NUM_FL_REGS<<2);
|
||||
sysbus_init_mmio(dev, &s->iomem);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cc32_flcon_reset(DeviceState *d)
|
||||
{
|
||||
cc32_flcon_state *s = container_of(d, cc32_flcon_state, busdev.qdev);
|
||||
|
||||
s->regs[FLBUF>>2] = 0xC0000 + (16*1024) - 512;
|
||||
}
|
||||
|
||||
static void cc32_flcon_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
|
||||
|
||||
sdc->init = cc32_flcon_init;
|
||||
dc->reset = cc32_flcon_reset;
|
||||
}
|
||||
|
||||
static TypeInfo cc32_flcon_info = {
|
||||
.name = "cc32-flcon",
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(cc32_flcon_state),
|
||||
.class_init = cc32_flcon_class_init,
|
||||
};
|
||||
|
||||
/***********************************************************************
|
||||
* System controller
|
||||
***********************************************************************/
|
||||
|
||||
enum cc32_sysc_reg {
|
||||
SCCM0 = 0x00,
|
||||
SCSYS = 0x04,
|
||||
|
@ -42,7 +237,7 @@ enum cc32_sysc_reg {
|
|||
SCCM4 = 0x7C,
|
||||
};
|
||||
|
||||
#define NUM_REGS (SCCM4 + 4)
|
||||
#define NUM_REGS ((SCCM4>>2) + 4)
|
||||
|
||||
typedef struct cc32_sysc_state
|
||||
{
|
||||
|
@ -105,6 +300,7 @@ static void cc32_sysc_write(void *opaque, target_phys_addr_t offset,
|
|||
switch (offset) {
|
||||
case SCINTEN:
|
||||
s->irq_enabled = value;
|
||||
fprintf(stderr, "cc32-sysc: INTEN = 0x%08x\n", s->irq_enabled);
|
||||
break;
|
||||
}
|
||||
cc32_sysc_update(s);
|
||||
|
@ -123,7 +319,7 @@ static int cc32_sysc_init(SysBusDevice *dev)
|
|||
qdev_init_gpio_in(&dev->qdev, cc32_sysc_set_irq, 32);
|
||||
sysbus_init_irq(dev, &s->parent_irq);
|
||||
sysbus_init_irq(dev, &s->parent_fiq);
|
||||
memory_region_init_io(&s->iomem, &cc32_sysc_ops, s, "cc32-sysc", 8);
|
||||
memory_region_init_io(&s->iomem, &cc32_sysc_ops, s, "cc32-sysc", NUM_REGS<<2);
|
||||
sysbus_init_mmio(dev, &s->iomem);
|
||||
|
||||
return 0;
|
||||
|
@ -156,11 +352,16 @@ static TypeInfo cc32_sysc_info = {
|
|||
static void cc32_register_types(void)
|
||||
{
|
||||
type_register_static(&cc32_sysc_info);
|
||||
type_register_static(&cc32_flcon_info);
|
||||
}
|
||||
|
||||
type_init(cc32_register_types)
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* SoC core
|
||||
***********************************************************************/
|
||||
|
||||
|
||||
struct arm_boot_info cc32rs512_binfo;
|
||||
|
||||
|
@ -177,6 +378,7 @@ static void cc32rs512_init(ram_addr_t ram_size,
|
|||
qemu_irq *cpu_irq;
|
||||
qemu_irq pic[32];
|
||||
DeviceState *dev;
|
||||
cc32_flcon_state *fl;
|
||||
int i;
|
||||
|
||||
if (!cpu_model)
|
||||
|
@ -187,13 +389,12 @@ static void cc32rs512_init(ram_addr_t ram_size,
|
|||
exit(1);
|
||||
}
|
||||
|
||||
memory_region_init_ram(flash, "cc32rs512.flash", 512*1024);
|
||||
memory_region_add_subregion(sysmem, 0, flash);
|
||||
|
||||
memory_region_init_ram(ram, "cc32rs512.ram", 16*1024);
|
||||
vmstate_register_ram_global(ram);
|
||||
memory_region_add_subregion(sysmem, 0xc0000, ram);
|
||||
|
||||
memory_region_init_ram(rsa_ram, "cc32rs512.rsa_ram", 2*1024);
|
||||
vmstate_register_ram_global(rsa_ram);
|
||||
memory_region_add_subregion(sysmem, 0xd4000, rsa_ram);
|
||||
|
||||
cc32rs512_binfo.ram_size = ram_size;
|
||||
|
@ -209,6 +410,15 @@ static void cc32rs512_init(ram_addr_t ram_size,
|
|||
|
||||
sysbus_create_simple("cc32-iso-slave", 0x0F8800, pic[8]);
|
||||
|
||||
dev = sysbus_create_simple("cc32-flcon", 0x0F2000, pic[6]);
|
||||
fl = container_of(dev, cc32_flcon_state, busdev.qdev);
|
||||
memory_region_init_rom_device(flash, &cc32_flash_ops, fl,
|
||||
"cc32rs512.flash", 512*1024);
|
||||
vmstate_register_ram_global(flash);
|
||||
fl->storage = memory_region_get_ram_ptr(flash);
|
||||
fl->ram_storage = memory_region_get_ram_ptr(ram);
|
||||
memory_region_add_subregion(sysmem, 0, flash);
|
||||
|
||||
arm_load_kernel(env, &cc32rs512_binfo);
|
||||
}
|
||||
|
||||
|
|
Reference in New Issue