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-14 14:24:59 +01:00
committed by Peter Maydell
parent 1351f89246
commit b821242c7b
7 changed files with 718 additions and 0 deletions
+1
View File
@@ -361,6 +361,7 @@ config NPCM7XX
select ARM_GIC
select PL310 # cache controller
select SERIAL
select SSI
select UNIMP
config FSL_IMX25
+58
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);
+1
View File
@@ -1,5 +1,6 @@
softmmu_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files('aspeed_smc.c'))
softmmu_ss.add(when: 'CONFIG_MSF2', if_true: files('mss-spi.c'))
softmmu_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_fiu.c'))
softmmu_ss.add(when: 'CONFIG_PL022', if_true: files('pl022.c'))
softmmu_ss.add(when: 'CONFIG_SSI', if_true: files('ssi.c'))
softmmu_ss.add(when: 'CONFIG_STM32F2XX_SPI', if_true: files('stm32f2xx_spi.c'))
File diff suppressed because it is too large Load Diff
+11
View File
@@ -9,3 +9,14 @@ aspeed_smc_dma_checksum(uint32_t addr, uint32_t data) "0x%08x: 0x%08x"
aspeed_smc_dma_rw(const char *dir, uint32_t flash_addr, uint32_t dram_addr, uint32_t size) "%s flash:@0x%08x dram:@0x%08x size:0x%08x"
aspeed_smc_write(uint64_t addr, uint32_t size, uint64_t data) "@0x%" PRIx64 " size %u: 0x%" PRIx64
aspeed_smc_flash_select(int cs, const char *prefix) "CS%d %sselect"
# npcm7xx_fiu.c
npcm7xx_fiu_enter_reset(const char *id, int reset_type) "%s reset type: %d"
npcm7xx_fiu_hold_reset(const char *id) "%s"
npcm7xx_fiu_select(const char *id, int cs) "%s select CS%d"
npcm7xx_fiu_deselect(const char *id, int cs) "%s deselect CS%d"
npcm7xx_fiu_ctrl_read(const char *id, uint64_t addr, uint32_t data) "%s offset: 0x%04" PRIx64 " value: 0x%08" PRIx32
npcm7xx_fiu_ctrl_write(const char *id, uint64_t addr, uint32_t data) "%s offset: 0x%04" PRIx64 " value: 0x%08" PRIx32
npcm7xx_fiu_flash_read(const char *id, int cs, uint64_t addr, unsigned int size, uint64_t value) "%s[%d] offset: 0x%08" PRIx64 " size: %u value: 0x%" PRIx64
npcm7xx_fiu_flash_write(const char *id, int cs, uint64_t addr, unsigned int size, uint64_t value) "%s[%d] offset: 0x%08" PRIx64 " size: %u value: 0x%" PRIx64
+2
View File
@@ -23,6 +23,7 @@
#include "hw/misc/npcm7xx_gcr.h"
#include "hw/nvram/npcm7xx_otp.h"
#include "hw/timer/npcm7xx_timer.h"
#include "hw/ssi/npcm7xx_fiu.h"
#include "target/arm/cpu.h"
#define NPCM7XX_MAX_NUM_CPUS (2)
@@ -73,6 +74,7 @@ typedef struct NPCM7xxState {
NPCM7xxOTPState key_storage;
NPCM7xxOTPState fuse_array;
NPCM7xxMCState mc;
NPCM7xxFIUState fiu[2];
} NPCM7xxState;
#define TYPE_NPCM7XX "npcm7xx"
+73
View File
@@ -0,0 +1,73 @@
/*
* Nuvoton NPCM7xx Flash Interface Unit (FIU)
*
* Copyright 2020 Google LLC
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#ifndef NPCM7XX_FIU_H
#define NPCM7XX_FIU_H
#include "hw/ssi/ssi.h"
#include "hw/sysbus.h"
/*
* Number of registers in our device state structure. Don't change this without
* incrementing the version_id in the vmstate.
*/
#define NPCM7XX_FIU_NR_REGS (0x7c / sizeof(uint32_t))
typedef struct NPCM7xxFIUState NPCM7xxFIUState;
/**
* struct NPCM7xxFIUFlash - Per-chipselect flash controller state.
* @direct_access: Memory region for direct flash access.
* @fiu: Pointer to flash controller shared state.
*/
typedef struct NPCM7xxFIUFlash {
MemoryRegion direct_access;
NPCM7xxFIUState *fiu;
} NPCM7xxFIUFlash;
/**
* NPCM7xxFIUState - Device state for one Flash Interface Unit.
* @parent: System bus device.
* @mmio: Memory region for register access.
* @cs_count: Number of flash chips that may be connected to this module.
* @active_cs: Currently active chip select, or -1 if no chip is selected.
* @cs_lines: GPIO lines that may be wired to flash chips.
* @flash: Array of @cs_count per-flash-chip state objects.
* @spi: The SPI bus mastered by this controller.
* @regs: Register contents.
*
* Each FIU has a shared bank of registers, and controls up to four chip
* selects. Each chip select has a dedicated memory region which may be used to
* read and write the flash connected to that chip select as if it were memory.
*/
struct NPCM7xxFIUState {
SysBusDevice parent;
MemoryRegion mmio;
int32_t cs_count;
int32_t active_cs;
qemu_irq *cs_lines;
NPCM7xxFIUFlash *flash;
SSIBus *spi;
uint32_t regs[NPCM7XX_FIU_NR_REGS];
};
#define TYPE_NPCM7XX_FIU "npcm7xx-fiu"
#define NPCM7XX_FIU(obj) OBJECT_CHECK(NPCM7xxFIUState, (obj), TYPE_NPCM7XX_FIU)
#endif /* NPCM7XX_FIU_H */