sim-card
/
qemu
Archived
10
0
Fork 0

cc32rs512: add simulation of the built-in flash controller

This commit is contained in:
Harald Welte 2012-03-04 18:17:53 +01:00
parent a4fb8f496a
commit 0aafdf2366
1 changed files with 215 additions and 5 deletions

View File

@ -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);
}