hw/ssi: NPCM7xx Flash Interface Unit device model

This implements a device model for the NPCM7xx SPI flash controller.

Direct reads and writes, and user-mode transactions have been tested in
various modes. Protection features are not implemented yet.

All the FIU instances are available in the SoC's address space,
regardless of whether or not they're connected to actual flash chips.

Reviewed-by: Tyrone Ting <kfting@nuvoton.com>
Reviewed-by: Cédric Le Goater <clg@kaod.org>
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
Tested-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
Tested-by: Alexander Bulekov <alxndr@bu.edu>
Signed-off-by: Havard Skinnemoen <hskinnemoen@google.com>
Message-id: 20200911052101.2602693-11-hskinnemoen@google.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Havard Skinnemoen 2020-09-10 22:20:57 -07:00 committed by Peter Maydell
parent 1351f89246
commit b821242c7b
7 changed files with 718 additions and 0 deletions

View file

@ -361,6 +361,7 @@ config NPCM7XX
select ARM_GIC
select PL310 # cache controller
select SERIAL
select SSI
select UNIMP
config FSL_IMX25

View file

@ -99,6 +99,39 @@ static const hwaddr npcm7xx_uart_addr[] = {
0xf0004000,
};
/* Direct memory-mapped access to SPI0 CS0-1. */
static const hwaddr npcm7xx_fiu0_flash_addr[] = {
0x80000000, /* CS0 */
0x88000000, /* CS1 */
};
/* Direct memory-mapped access to SPI3 CS0-3. */
static const hwaddr npcm7xx_fiu3_flash_addr[] = {
0xa0000000, /* CS0 */
0xa8000000, /* CS1 */
0xb0000000, /* CS2 */
0xb8000000, /* CS3 */
};
static const struct {
const char *name;
hwaddr regs_addr;
int cs_count;
const hwaddr *flash_addr;
} npcm7xx_fiu[] = {
{
.name = "fiu0",
.regs_addr = 0xfb000000,
.cs_count = ARRAY_SIZE(npcm7xx_fiu0_flash_addr),
.flash_addr = npcm7xx_fiu0_flash_addr,
}, {
.name = "fiu3",
.regs_addr = 0xc0000000,
.cs_count = ARRAY_SIZE(npcm7xx_fiu3_flash_addr),
.flash_addr = npcm7xx_fiu3_flash_addr,
},
};
static void npcm7xx_write_secondary_boot(ARMCPU *cpu,
const struct arm_boot_info *info)
{
@ -192,6 +225,12 @@ static void npcm7xx_init(Object *obj)
for (i = 0; i < ARRAY_SIZE(s->tim); i++) {
object_initialize_child(obj, "tim[*]", &s->tim[i], TYPE_NPCM7XX_TIMER);
}
QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm7xx_fiu) != ARRAY_SIZE(s->fiu));
for (i = 0; i < ARRAY_SIZE(s->fiu); i++) {
object_initialize_child(obj, npcm7xx_fiu[i].name, &s->fiu[i],
TYPE_NPCM7XX_FIU);
}
}
static void npcm7xx_realize(DeviceState *dev, Error **errp)
@ -291,6 +330,25 @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
serial_hd(i), DEVICE_LITTLE_ENDIAN);
}
/*
* Flash Interface Unit (FIU). Can fail if incorrect number of chip selects
* specified, but this is a programming error.
*/
QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm7xx_fiu) != ARRAY_SIZE(s->fiu));
for (i = 0; i < ARRAY_SIZE(s->fiu); i++) {
SysBusDevice *sbd = SYS_BUS_DEVICE(&s->fiu[i]);
int j;
object_property_set_int(OBJECT(sbd), "cs-count",
npcm7xx_fiu[i].cs_count, &error_abort);
sysbus_realize(sbd, &error_abort);
sysbus_mmio_map(sbd, 0, npcm7xx_fiu[i].regs_addr);
for (j = 0; j < npcm7xx_fiu[i].cs_count; j++) {
sysbus_mmio_map(sbd, j + 1, npcm7xx_fiu[i].flash_addr[j]);
}
}
/* RAM2 (SRAM) */
memory_region_init_ram(&s->sram, OBJECT(dev), "ram2",
NPCM7XX_RAM2_SZ, &error_abort);