diff options
Diffstat (limited to 'hw')
-rw-r--r-- | hw/block/m25p80.c | 57 | ||||
-rw-r--r-- | hw/misc/sifive_u_otp.c | 13 | ||||
-rw-r--r-- | hw/riscv/Kconfig | 3 | ||||
-rw-r--r-- | hw/riscv/microchip_pfsoc.c | 9 | ||||
-rw-r--r-- | hw/riscv/opentitan.c | 9 | ||||
-rw-r--r-- | hw/riscv/sifive_e.c | 9 | ||||
-rw-r--r-- | hw/riscv/sifive_u.c | 102 | ||||
-rw-r--r-- | hw/riscv/spike.c | 9 | ||||
-rw-r--r-- | hw/riscv/virt.c | 68 | ||||
-rw-r--r-- | hw/rtc/goldfish_rtc.c | 2 | ||||
-rw-r--r-- | hw/ssi/Kconfig | 4 | ||||
-rw-r--r-- | hw/ssi/meson.build | 1 | ||||
-rw-r--r-- | hw/ssi/sifive_spi.c | 358 |
13 files changed, 589 insertions, 55 deletions
diff --git a/hw/block/m25p80.c b/hw/block/m25p80.c index 0412d3e7f4..5f9471d83c 100644 --- a/hw/block/m25p80.c +++ b/hw/block/m25p80.c @@ -210,6 +210,19 @@ static const FlashPartInfo known_devices[] = { { INFO("640s33b", 0x898913, 0, 64 << 10, 128, 0) }, { INFO("n25q064", 0x20ba17, 0, 64 << 10, 128, 0) }, + /* ISSI */ + { INFO("is25lq040b", 0x9d4013, 0, 64 << 10, 8, ER_4K) }, + { INFO("is25lp080d", 0x9d6014, 0, 64 << 10, 16, ER_4K) }, + { INFO("is25lp016d", 0x9d6015, 0, 64 << 10, 32, ER_4K) }, + { INFO("is25lp032", 0x9d6016, 0, 64 << 10, 64, ER_4K) }, + { INFO("is25lp064", 0x9d6017, 0, 64 << 10, 128, ER_4K) }, + { INFO("is25lp128", 0x9d6018, 0, 64 << 10, 256, ER_4K) }, + { INFO("is25lp256", 0x9d6019, 0, 64 << 10, 512, ER_4K) }, + { INFO("is25wp032", 0x9d7016, 0, 64 << 10, 64, ER_4K) }, + { INFO("is25wp064", 0x9d7017, 0, 64 << 10, 128, ER_4K) }, + { INFO("is25wp128", 0x9d7018, 0, 64 << 10, 256, ER_4K) }, + { INFO("is25wp256", 0x9d7019, 0, 64 << 10, 512, ER_4K) }, + /* Macronix */ { INFO("mx25l2005a", 0xc22012, 0, 64 << 10, 4, ER_4K) }, { INFO("mx25l4005a", 0xc22013, 0, 64 << 10, 8, ER_4K) }, @@ -412,6 +425,7 @@ typedef enum { MAN_NUMONYX, MAN_WINBOND, MAN_SST, + MAN_ISSI, MAN_GENERIC, } Manufacturer; @@ -487,6 +501,8 @@ static inline Manufacturer get_man(Flash *s) return MAN_MACRONIX; case 0xBF: return MAN_SST; + case 0x9D: + return MAN_ISSI; default: return MAN_GENERIC; } @@ -706,6 +722,9 @@ static void complete_collecting_data(Flash *s) case MAN_SPANSION: s->quad_enable = !!(s->data[1] & 0x02); break; + case MAN_ISSI: + s->quad_enable = extract32(s->data[0], 6, 1); + break; case MAN_MACRONIX: s->quad_enable = extract32(s->data[0], 6, 1); if (s->len > 1) { @@ -895,6 +914,19 @@ static void decode_fast_read_cmd(Flash *s) SPANSION_DUMMY_CLK_LEN ); break; + case MAN_ISSI: + /* + * The Fast Read instruction code is followed by address bytes and + * dummy cycles, transmitted via the SI line. + * + * The number of dummy cycles is configurable but this is currently + * unmodeled, hence the default value 8 is used. + * + * QPI (Quad Peripheral Interface) mode has different default value + * of dummy cycles, but this is unsupported at the time being. + */ + s->needed_bytes += 1; + break; default: break; } @@ -934,6 +966,16 @@ static void decode_dio_read_cmd(Flash *s) break; } break; + case MAN_ISSI: + /* + * The Fast Read Dual I/O instruction code is followed by address bytes + * and dummy cycles, transmitted via the IO1 and IO0 line. + * + * The number of dummy cycles is configurable but this is currently + * unmodeled, hence the default value 4 is used. + */ + s->needed_bytes += 1; + break; default: break; } @@ -974,6 +1016,19 @@ static void decode_qio_read_cmd(Flash *s) break; } break; + case MAN_ISSI: + /* + * The Fast Read Quad I/O instruction code is followed by address bytes + * and dummy cycles, transmitted via the IO3, IO2, IO1 and IO0 line. + * + * The number of dummy cycles is configurable but this is currently + * unmodeled, hence the default value 6 is used. + * + * QPI (Quad Peripheral Interface) mode has different default value + * of dummy cycles, but this is unsupported at the time being. + */ + s->needed_bytes += 3; + break; default: break; } @@ -1132,7 +1187,7 @@ static void decode_new_cmd(Flash *s, uint32_t value) case RDSR: s->data[0] = (!!s->write_enable) << 1; - if (get_man(s) == MAN_MACRONIX) { + if (get_man(s) == MAN_MACRONIX || get_man(s) == MAN_ISSI) { s->data[0] |= (!!s->quad_enable) << 6; } if (get_man(s) == MAN_SST) { diff --git a/hw/misc/sifive_u_otp.c b/hw/misc/sifive_u_otp.c index b8e8b9eebe..18aa0bd55d 100644 --- a/hw/misc/sifive_u_otp.c +++ b/hw/misc/sifive_u_otp.c @@ -23,6 +23,7 @@ #include "hw/qdev-properties.h" #include "hw/qdev-properties-system.h" #include "hw/sysbus.h" +#include "qemu/error-report.h" #include "qemu/log.h" #include "qemu/module.h" #include "hw/misc/sifive_u_otp.h" @@ -65,8 +66,7 @@ static uint64_t sifive_u_otp_read(void *opaque, hwaddr addr, unsigned int size) if (blk_pread(s->blk, s->pa * SIFIVE_U_OTP_FUSE_WORD, &buf, SIFIVE_U_OTP_FUSE_WORD) < 0) { - qemu_log_mask(LOG_GUEST_ERROR, - "read error index<%d>\n", s->pa); + error_report("read error index<%d>", s->pa); return 0xff; } @@ -169,8 +169,7 @@ static void sifive_u_otp_write(void *opaque, hwaddr addr, if (blk_pwrite(s->blk, s->pa * SIFIVE_U_OTP_FUSE_WORD, &s->fuse[s->pa], SIFIVE_U_OTP_FUSE_WORD, 0) < 0) { - qemu_log_mask(LOG_GUEST_ERROR, - "write error index<%d>\n", s->pa); + error_report("write error index<%d>", s->pa); } } @@ -260,15 +259,13 @@ static void sifive_u_otp_reset(DeviceState *dev) serial_data = s->serial; if (blk_pwrite(s->blk, index * SIFIVE_U_OTP_FUSE_WORD, &serial_data, SIFIVE_U_OTP_FUSE_WORD, 0) < 0) { - qemu_log_mask(LOG_GUEST_ERROR, - "write error index<%d>\n", index); + error_report("write error index<%d>", index); } serial_data = ~(s->serial); if (blk_pwrite(s->blk, (index + 1) * SIFIVE_U_OTP_FUSE_WORD, &serial_data, SIFIVE_U_OTP_FUSE_WORD, 0) < 0) { - qemu_log_mask(LOG_GUEST_ERROR, - "write error index<%d>\n", index + 1); + error_report("write error index<%d>", index + 1); } } diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig index facb0cbacc..d139074b02 100644 --- a/hw/riscv/Kconfig +++ b/hw/riscv/Kconfig @@ -52,9 +52,12 @@ config SIFIVE_U select SIFIVE_GPIO select SIFIVE_PDMA select SIFIVE_PLIC + select SIFIVE_SPI select SIFIVE_UART select SIFIVE_U_OTP select SIFIVE_U_PRCI + select SSI_M25P80 + select SSI_SD select UNIMP config SPIKE diff --git a/hw/riscv/microchip_pfsoc.c b/hw/riscv/microchip_pfsoc.c index e952b49e8c..266f1c3342 100644 --- a/hw/riscv/microchip_pfsoc.c +++ b/hw/riscv/microchip_pfsoc.c @@ -86,10 +86,7 @@ * - Register Map/PF_SoC_RegMap_V1_1/MPFS250T/mpfs250t_ioscb_memmap_dri.htm * describes the complete IOSCB modules memory maps */ -static const struct MemmapEntry { - hwaddr base; - hwaddr size; -} microchip_pfsoc_memmap[] = { +static const MemMapEntry microchip_pfsoc_memmap[] = { [MICROCHIP_PFSOC_RSVD0] = { 0x0, 0x100 }, [MICROCHIP_PFSOC_DEBUG] = { 0x100, 0xf00 }, [MICROCHIP_PFSOC_E51_DTIM] = { 0x1000000, 0x2000 }, @@ -182,7 +179,7 @@ static void microchip_pfsoc_soc_realize(DeviceState *dev, Error **errp) { MachineState *ms = MACHINE(qdev_get_machine()); MicrochipPFSoCState *s = MICROCHIP_PFSOC(dev); - const struct MemmapEntry *memmap = microchip_pfsoc_memmap; + const MemMapEntry *memmap = microchip_pfsoc_memmap; MemoryRegion *system_memory = get_system_memory(); MemoryRegion *rsvd0_mem = g_new(MemoryRegion, 1); MemoryRegion *e51_dtim_mem = g_new(MemoryRegion, 1); @@ -451,7 +448,7 @@ type_init(microchip_pfsoc_soc_register_types) static void microchip_icicle_kit_machine_init(MachineState *machine) { MachineClass *mc = MACHINE_GET_CLASS(machine); - const struct MemmapEntry *memmap = microchip_pfsoc_memmap; + const MemMapEntry *memmap = microchip_pfsoc_memmap; MicrochipIcicleKitState *s = MICROCHIP_ICICLE_KIT_MACHINE(machine); MemoryRegion *system_memory = get_system_memory(); MemoryRegion *mem_low = g_new(MemoryRegion, 1); diff --git a/hw/riscv/opentitan.c b/hw/riscv/opentitan.c index af3456932f..e168bffe69 100644 --- a/hw/riscv/opentitan.c +++ b/hw/riscv/opentitan.c @@ -28,10 +28,7 @@ #include "qemu/units.h" #include "sysemu/sysemu.h" -static const struct MemmapEntry { - hwaddr base; - hwaddr size; -} ibex_memmap[] = { +static const MemMapEntry ibex_memmap[] = { [IBEX_DEV_ROM] = { 0x00008000, 16 * KiB }, [IBEX_DEV_RAM] = { 0x10000000, 0x10000 }, [IBEX_DEV_FLASH] = { 0x20000000, 0x80000 }, @@ -66,7 +63,7 @@ static const struct MemmapEntry { static void opentitan_board_init(MachineState *machine) { - const struct MemmapEntry *memmap = ibex_memmap; + const MemMapEntry *memmap = ibex_memmap; OpenTitanState *s = g_new0(OpenTitanState, 1); MemoryRegion *sys_mem = get_system_memory(); MemoryRegion *main_mem = g_new(MemoryRegion, 1); @@ -114,7 +111,7 @@ static void lowrisc_ibex_soc_init(Object *obj) static void lowrisc_ibex_soc_realize(DeviceState *dev_soc, Error **errp) { - const struct MemmapEntry *memmap = ibex_memmap; + const MemMapEntry *memmap = ibex_memmap; MachineState *ms = MACHINE(qdev_get_machine()); LowRISCIbexSoCState *s = RISCV_IBEX_SOC(dev_soc); MemoryRegion *sys_mem = get_system_memory(); diff --git a/hw/riscv/sifive_e.c b/hw/riscv/sifive_e.c index 59bac4cc9a..f939bcf9ea 100644 --- a/hw/riscv/sifive_e.c +++ b/hw/riscv/sifive_e.c @@ -50,10 +50,7 @@ #include "sysemu/sysemu.h" #include "exec/address-spaces.h" -static const struct MemmapEntry { - hwaddr base; - hwaddr size; -} sifive_e_memmap[] = { +static MemMapEntry sifive_e_memmap[] = { [SIFIVE_E_DEV_DEBUG] = { 0x0, 0x1000 }, [SIFIVE_E_DEV_MROM] = { 0x1000, 0x2000 }, [SIFIVE_E_DEV_OTP] = { 0x20000, 0x2000 }, @@ -77,7 +74,7 @@ static const struct MemmapEntry { static void sifive_e_machine_init(MachineState *machine) { - const struct MemmapEntry *memmap = sifive_e_memmap; + const MemMapEntry *memmap = sifive_e_memmap; SiFiveEState *s = RISCV_E_MACHINE(machine); MemoryRegion *sys_mem = get_system_memory(); @@ -187,7 +184,7 @@ static void sifive_e_soc_init(Object *obj) static void sifive_e_soc_realize(DeviceState *dev, Error **errp) { MachineState *ms = MACHINE(qdev_get_machine()); - const struct MemmapEntry *memmap = sifive_e_memmap; + const MemMapEntry *memmap = sifive_e_memmap; SiFiveESoCState *s = RISCV_E_SOC(dev); MemoryRegion *sys_mem = get_system_memory(); diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c index 59b61cea01..7b59942369 100644 --- a/hw/riscv/sifive_u.c +++ b/hw/riscv/sifive_u.c @@ -15,6 +15,8 @@ * 5) OTP (One-Time Programmable) memory with stored serial number * 6) GEM (Gigabit Ethernet Controller) and management block * 7) DMA (Direct Memory Access Controller) + * 8) SPI0 connected to an SPI flash + * 9) SPI2 connected to an SD card * * This board currently generates devicetree dynamically that indicates at least * two harts and up to five harts. @@ -44,6 +46,7 @@ #include "hw/char/serial.h" #include "hw/cpu/cluster.h" #include "hw/misc/unimp.h" +#include "hw/ssi/ssi.h" #include "target/riscv/cpu.h" #include "hw/riscv/riscv_hart.h" #include "hw/riscv/sifive_u.h" @@ -60,10 +63,7 @@ #include <libfdt.h> -static const struct MemmapEntry { - hwaddr base; - hwaddr size; -} sifive_u_memmap[] = { +static const MemMapEntry sifive_u_memmap[] = { [SIFIVE_U_DEV_DEBUG] = { 0x0, 0x100 }, [SIFIVE_U_DEV_MROM] = { 0x1000, 0xf000 }, [SIFIVE_U_DEV_CLINT] = { 0x2000000, 0x10000 }, @@ -74,6 +74,8 @@ static const struct MemmapEntry { [SIFIVE_U_DEV_PRCI] = { 0x10000000, 0x1000 }, [SIFIVE_U_DEV_UART0] = { 0x10010000, 0x1000 }, [SIFIVE_U_DEV_UART1] = { 0x10011000, 0x1000 }, + [SIFIVE_U_DEV_QSPI0] = { 0x10040000, 0x1000 }, + [SIFIVE_U_DEV_QSPI2] = { 0x10050000, 0x1000 }, [SIFIVE_U_DEV_GPIO] = { 0x10060000, 0x1000 }, [SIFIVE_U_DEV_OTP] = { 0x10070000, 0x1000 }, [SIFIVE_U_DEV_GEM] = { 0x10090000, 0x2000 }, @@ -86,7 +88,7 @@ static const struct MemmapEntry { #define OTP_SERIAL 1 #define GEM_REVISION 0x10070109 -static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap, +static void create_fdt(SiFiveUState *s, const MemMapEntry *memmap, uint64_t mem_size, const char *cmdline, bool is_32_bit) { MachineState *ms = MACHINE(qdev_get_machine()); @@ -342,6 +344,57 @@ static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap, "sifive,fu540-c000-ccache"); g_free(nodename); + nodename = g_strdup_printf("/soc/spi@%lx", + (long)memmap[SIFIVE_U_DEV_QSPI2].base); + qemu_fdt_add_subnode(fdt, nodename); + qemu_fdt_setprop_cell(fdt, nodename, "#size-cells", 0); + qemu_fdt_setprop_cell(fdt, nodename, "#address-cells", 1); + qemu_fdt_setprop_cells(fdt, nodename, "clocks", + prci_phandle, PRCI_CLK_TLCLK); + qemu_fdt_setprop_cell(fdt, nodename, "interrupts", SIFIVE_U_QSPI2_IRQ); + qemu_fdt_setprop_cell(fdt, nodename, "interrupt-parent", plic_phandle); + qemu_fdt_setprop_cells(fdt, nodename, "reg", + 0x0, memmap[SIFIVE_U_DEV_QSPI2].base, + 0x0, memmap[SIFIVE_U_DEV_QSPI2].size); + qemu_fdt_setprop_string(fdt, nodename, "compatible", "sifive,spi0"); + g_free(nodename); + + nodename = g_strdup_printf("/soc/spi@%lx/mmc@0", + (long)memmap[SIFIVE_U_DEV_QSPI2].base); + qemu_fdt_add_subnode(fdt, nodename); + qemu_fdt_setprop(fdt, nodename, "disable-wp", NULL, 0); + qemu_fdt_setprop_cells(fdt, nodename, "voltage-ranges", 3300, 3300); + qemu_fdt_setprop_cell(fdt, nodename, "spi-max-frequency", 20000000); + qemu_fdt_setprop_cell(fdt, nodename, "reg", 0); + qemu_fdt_setprop_string(fdt, nodename, "compatible", "mmc-spi-slot"); + g_free(nodename); + + nodename = g_strdup_printf("/soc/spi@%lx", + (long)memmap[SIFIVE_U_DEV_QSPI0].base); + qemu_fdt_add_subnode(fdt, nodename); + qemu_fdt_setprop_cell(fdt, nodename, "#size-cells", 0); + qemu_fdt_setprop_cell(fdt, nodename, "#address-cells", 1); + qemu_fdt_setprop_cells(fdt, nodename, "clocks", + prci_phandle, PRCI_CLK_TLCLK); + qemu_fdt_setprop_cell(fdt, nodename, "interrupts", SIFIVE_U_QSPI0_IRQ); + qemu_fdt_setprop_cell(fdt, nodename, "interrupt-parent", plic_phandle); + qemu_fdt_setprop_cells(fdt, nodename, "reg", + 0x0, memmap[SIFIVE_U_DEV_QSPI0].base, + 0x0, memmap[SIFIVE_U_DEV_QSPI0].size); + qemu_fdt_setprop_string(fdt, nodename, "compatible", "sifive,spi0"); + g_free(nodename); + + nodename = g_strdup_printf("/soc/spi@%lx/flash@0", + (long)memmap[SIFIVE_U_DEV_QSPI0].base); + qemu_fdt_add_subnode(fdt, nodename); + qemu_fdt_setprop_cell(fdt, nodename, "spi-rx-bus-width", 4); + qemu_fdt_setprop_cell(fdt, nodename, "spi-tx-bus-width", 4); + qemu_fdt_setprop(fdt, nodename, "m25p,fast-read", NULL, 0); + qemu_fdt_setprop_cell(fdt, nodename, "spi-max-frequency", 50000000); + qemu_fdt_setprop_cell(fdt, nodename, "reg", 0); + qemu_fdt_setprop_string(fdt, nodename, "compatible", "jedec,spi-nor"); + g_free(nodename); + phy_phandle = phandle++; nodename = g_strdup_printf("/soc/ethernet@%lx", (long)memmap[SIFIVE_U_DEV_GEM].base); @@ -428,7 +481,7 @@ static void sifive_u_machine_reset(void *opaque, int n, int level) static void sifive_u_machine_init(MachineState *machine) { - const struct MemmapEntry *memmap = sifive_u_memmap; + const MemMapEntry *memmap = sifive_u_memmap; SiFiveUState *s = RISCV_U_MACHINE(machine); MemoryRegion *system_memory = get_system_memory(); MemoryRegion *main_mem = g_new(MemoryRegion, 1); @@ -439,6 +492,9 @@ static void sifive_u_machine_init(MachineState *machine) int i; uint32_t fdt_load_addr; uint64_t kernel_entry; + DriveInfo *dinfo; + DeviceState *flash_dev, *sd_dev; + qemu_irq flash_cs, sd_cs; /* Initialize SoC */ object_initialize_child(OBJECT(machine), "soc", &s->soc, TYPE_RISCV_U_SOC); @@ -571,6 +627,25 @@ static void sifive_u_machine_init(MachineState *machine) riscv_rom_copy_firmware_info(machine, memmap[SIFIVE_U_DEV_MROM].base, memmap[SIFIVE_U_DEV_MROM].size, sizeof(reset_vec), kernel_entry); + + /* Connect an SPI flash to SPI0 */ + flash_dev = qdev_new("is25wp256"); + dinfo = drive_get_next(IF_MTD); + if (dinfo) { + qdev_prop_set_drive_err(flash_dev, "drive", + blk_by_legacy_dinfo(dinfo), + &error_fatal); + } + qdev_realize_and_unref(flash_dev, BUS(s->soc.spi0.spi), &error_fatal); + + flash_cs = qdev_get_gpio_in_named(flash_dev, SSI_GPIO_CS, 0); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->soc.spi0), 1, flash_cs); + + /* Connect an SD card to SPI2 */ + sd_dev = ssi_create_peripheral(s->soc.spi2.spi, "ssi-sd"); + + sd_cs = qdev_get_gpio_in_named(sd_dev, SSI_GPIO_CS, 0); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->soc.spi2), 1, sd_cs); } static bool sifive_u_machine_get_start_in_flash(Object *obj, Error **errp) @@ -680,13 +755,15 @@ static void sifive_u_soc_instance_init(Object *obj) object_initialize_child(obj, "gem", &s->gem, TYPE_CADENCE_GEM); object_initialize_child(obj, "gpio", &s->gpio, TYPE_SIFIVE_GPIO); object_initialize_child(obj, "pdma", &s->dma, TYPE_SIFIVE_PDMA); + object_initialize_child(obj, "spi0", &s->spi0, TYPE_SIFIVE_SPI); + object_initialize_child(obj, "spi2", &s->spi2, TYPE_SIFIVE_SPI); } static void sifive_u_soc_realize(DeviceState *dev, Error **errp) { MachineState *ms = MACHINE(qdev_get_machine()); SiFiveUSoCState *s = RISCV_U_SOC(dev); - const struct MemmapEntry *memmap = sifive_u_memmap; + const MemMapEntry *memmap = sifive_u_memmap; MemoryRegion *system_memory = get_system_memory(); MemoryRegion *mask_rom = g_new(MemoryRegion, 1); MemoryRegion *l2lim_mem = g_new(MemoryRegion, 1); @@ -827,6 +904,17 @@ static void sifive_u_soc_realize(DeviceState *dev, Error **errp) create_unimplemented_device("riscv.sifive.u.l2cc", memmap[SIFIVE_U_DEV_L2CC].base, memmap[SIFIVE_U_DEV_L2CC].size); + + sysbus_realize(SYS_BUS_DEVICE(&s->spi0), errp); + sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi0), 0, + memmap[SIFIVE_U_DEV_QSPI0].base); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->spi0), 0, + qdev_get_gpio_in(DEVICE(s->plic), SIFIVE_U_QSPI0_IRQ)); + sysbus_realize(SYS_BUS_DEVICE(&s->spi2), errp); + sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi2), 0, + memmap[SIFIVE_U_DEV_QSPI2].base); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->spi2), 0, + qdev_get_gpio_in(DEVICE(s->plic), SIFIVE_U_QSPI2_IRQ)); } static Property sifive_u_soc_props[] = { diff --git a/hw/riscv/spike.c b/hw/riscv/spike.c index 56986ecfe0..ed4ca9808e 100644 --- a/hw/riscv/spike.c +++ b/hw/riscv/spike.c @@ -43,16 +43,13 @@ #include "sysemu/qtest.h" #include "sysemu/sysemu.h" -static const struct MemmapEntry { - hwaddr base; - hwaddr size; -} spike_memmap[] = { +static const MemMapEntry spike_memmap[] = { [SPIKE_MROM] = { 0x1000, 0xf000 }, [SPIKE_CLINT] = { 0x2000000, 0x10000 }, [SPIKE_DRAM] = { 0x80000000, 0x0 }, }; -static void create_fdt(SpikeState *s, const struct MemmapEntry *memmap, +static void create_fdt(SpikeState *s, const MemMapEntry *memmap, uint64_t mem_size, const char *cmdline, bool is_32_bit) { void *fdt; @@ -179,7 +176,7 @@ static void create_fdt(SpikeState *s, const struct MemmapEntry *memmap, static void spike_board_init(MachineState *machine) { - const struct MemmapEntry *memmap = spike_memmap; + const MemMapEntry *memmap = spike_memmap; SpikeState *s = SPIKE_MACHINE(machine); MemoryRegion *system_memory = get_system_memory(); MemoryRegion *main_mem = g_new(MemoryRegion, 1); diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index 2299b3a6be..4f0c2fbca0 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -43,10 +43,7 @@ #include "hw/pci/pci.h" #include "hw/pci-host/gpex.h" -static const struct MemmapEntry { - hwaddr base; - hwaddr size; -} virt_memmap[] = { +static const MemMapEntry virt_memmap[] = { [VIRT_DEBUG] = { 0x0, 0x100 }, [VIRT_MROM] = { 0x1000, 0xf000 }, [VIRT_TEST] = { 0x100000, 0x1000 }, @@ -62,6 +59,15 @@ static const struct MemmapEntry { [VIRT_DRAM] = { 0x80000000, 0x0 }, }; +/* PCIe high mmio is fixed for RV32 */ +#define VIRT32_HIGH_PCIE_MMIO_BASE 0x300000000ULL +#define VIRT32_HIGH_PCIE_MMIO_SIZE (4 * GiB) + +/* PCIe high mmio for RV64, size is fixed but base depends on top of RAM */ +#define VIRT64_HIGH_PCIE_MMIO_SIZE (16 * GiB) + +static MemMapEntry virt_high_pcie_memmap; + #define VIRT_FLASH_SECTOR_SIZE (256 * KiB) static PFlashCFI01 *virt_flash_create1(RISCVVirtState *s, @@ -170,7 +176,7 @@ static void create_pcie_irq_map(void *fdt, char *nodename, 0x1800, 0, 0, 0x7); } -static void create_fdt(RISCVVirtState *s, const struct MemmapEntry *memmap, +static void create_fdt(RISCVVirtState *s, const MemMapEntry *memmap, uint64_t mem_size, const char *cmdline, bool is_32_bit) { void *fdt; @@ -374,7 +380,11 @@ static void create_fdt(RISCVVirtState *s, const struct MemmapEntry *memmap, 2, memmap[VIRT_PCIE_PIO].base, 2, memmap[VIRT_PCIE_PIO].size, 1, FDT_PCI_RANGE_MMIO, 2, memmap[VIRT_PCIE_MMIO].base, - 2, memmap[VIRT_PCIE_MMIO].base, 2, memmap[VIRT_PCIE_MMIO].size); + 2, memmap[VIRT_PCIE_MMIO].base, 2, memmap[VIRT_PCIE_MMIO].size, + 1, FDT_PCI_RANGE_MMIO_64BIT, + 2, virt_high_pcie_memmap.base, + 2, virt_high_pcie_memmap.base, 2, virt_high_pcie_memmap.size); + create_pcie_irq_map(fdt, name, plic_pcie_phandle); g_free(name); @@ -451,12 +461,14 @@ update_bootargs: static inline DeviceState *gpex_pcie_init(MemoryRegion *sys_mem, hwaddr ecam_base, hwaddr ecam_size, hwaddr mmio_base, hwaddr mmio_size, + hwaddr high_mmio_base, + hwaddr high_mmio_size, hwaddr pio_base, - DeviceState *plic, bool link_up) + DeviceState *plic) { DeviceState *dev; MemoryRegion *ecam_alias, *ecam_reg; - MemoryRegion *mmio_alias, *mmio_reg; + MemoryRegion *mmio_alias, *high_mmio_alias, *mmio_reg; qemu_irq irq; int i; @@ -476,6 +488,13 @@ static inline DeviceState *gpex_pcie_init(MemoryRegion *sys_mem, mmio_reg, mmio_base, mmio_size); memory_region_add_subregion(get_system_memory(), mmio_base, mmio_alias); + /* Map high MMIO space */ + high_mmio_alias = g_new0(MemoryRegion, 1); + memory_region_init_alias(high_mmio_alias, OBJECT(dev), "pcie-mmio-high", + mmio_reg, high_mmio_base, high_mmio_size); + memory_region_add_subregion(get_system_memory(), high_mmio_base, + high_mmio_alias); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, pio_base); for (i = 0; i < GPEX_NUM_IRQS; i++) { @@ -490,7 +509,7 @@ static inline DeviceState *gpex_pcie_init(MemoryRegion *sys_mem, static void virt_machine_init(MachineState *machine) { - const struct MemmapEntry *memmap = virt_memmap; + const MemMapEntry *memmap = virt_memmap; RISCVVirtState *s = RISCV_VIRT_MACHINE(machine); MemoryRegion *system_memory = get_system_memory(); MemoryRegion *main_mem = g_new(MemoryRegion, 1); @@ -593,6 +612,23 @@ static void virt_machine_init(MachineState *machine) } } + if (riscv_is_32bit(&s->soc[0])) { +#if HOST_LONG_BITS == 64 + /* limit RAM size in a 32-bit system */ + if (machine->ram_size > 10 * GiB) { + machine->ram_size = 10 * GiB; + error_report("Limiting RAM size to 10 GiB"); + } +#endif + virt_high_pcie_memmap.base = VIRT32_HIGH_PCIE_MMIO_BASE; + virt_high_pcie_memmap.size = VIRT32_HIGH_PCIE_MMIO_SIZE; + } else { + virt_high_pcie_memmap.size = VIRT64_HIGH_PCIE_MMIO_SIZE; + virt_high_pcie_memmap.base = memmap[VIRT_DRAM].base + machine->ram_size; + virt_high_pcie_memmap.base = + ROUND_UP(virt_high_pcie_memmap.base, virt_high_pcie_memmap.size); + } + /* register system main memory (actual RAM) */ memory_region_init_ram(main_mem, NULL, "riscv_virt_board.ram", machine->ram_size, &error_fatal); @@ -672,12 +708,14 @@ static void virt_machine_init(MachineState *machine) } gpex_pcie_init(system_memory, - memmap[VIRT_PCIE_ECAM].base, - memmap[VIRT_PCIE_ECAM].size, - memmap[VIRT_PCIE_MMIO].base, - memmap[VIRT_PCIE_MMIO].size, - memmap[VIRT_PCIE_PIO].base, - DEVICE(pcie_plic), true); + memmap[VIRT_PCIE_ECAM].base, + memmap[VIRT_PCIE_ECAM].size, + memmap[VIRT_PCIE_MMIO].base, + memmap[VIRT_PCIE_MMIO].size, + virt_high_pcie_memmap.base, + virt_high_pcie_memmap.size, + memmap[VIRT_PCIE_PIO].base, + DEVICE(pcie_plic)); serial_mm_init(system_memory, memmap[VIRT_UART0].base, 0, qdev_get_gpio_in(DEVICE(mmio_plic), UART0_IRQ), 399193, diff --git a/hw/rtc/goldfish_rtc.c b/hw/rtc/goldfish_rtc.c index 0f4e8185a7..e07ff0164e 100644 --- a/hw/rtc/goldfish_rtc.c +++ b/hw/rtc/goldfish_rtc.c @@ -211,6 +211,8 @@ static int goldfish_rtc_post_load(void *opaque, int version_id) qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); s->tick_offset = s->tick_offset_vmstate - delta; + goldfish_rtc_set_alarm(s); + return 0; } diff --git a/hw/ssi/Kconfig b/hw/ssi/Kconfig index 9e54a0c8dd..7d90a02181 100644 --- a/hw/ssi/Kconfig +++ b/hw/ssi/Kconfig @@ -2,6 +2,10 @@ config PL022 bool select SSI +config SIFIVE_SPI + bool + select SSI + config SSI bool diff --git a/hw/ssi/meson.build b/hw/ssi/meson.build index dee00c0da6..3d6bc82ab1 100644 --- a/hw/ssi/meson.build +++ b/hw/ssi/meson.build @@ -2,6 +2,7 @@ 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_SIFIVE_SPI', if_true: files('sifive_spi.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')) softmmu_ss.add(when: 'CONFIG_XILINX_SPI', if_true: files('xilinx_spi.c')) diff --git a/hw/ssi/sifive_spi.c b/hw/ssi/sifive_spi.c new file mode 100644 index 0000000000..0c9ebca3c8 --- /dev/null +++ b/hw/ssi/sifive_spi.c @@ -0,0 +1,358 @@ +/* + * QEMU model of the SiFive SPI Controller + * + * Copyright (c) 2021 Wind River Systems, Inc. + * + * Author: + * Bin Meng <bin.meng@windriver.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2 or later, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "qemu/osdep.h" +#include "hw/irq.h" +#include "hw/qdev-properties.h" +#include "hw/sysbus.h" +#include "hw/ssi/ssi.h" +#include "sysemu/sysemu.h" +#include "qemu/fifo8.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "hw/ssi/sifive_spi.h" + +#define R_SCKDIV (0x00 / 4) +#define R_SCKMODE (0x04 / 4) +#define R_CSID (0x10 / 4) +#define R_CSDEF (0x14 / 4) +#define R_CSMODE (0x18 / 4) +#define R_DELAY0 (0x28 / 4) +#define R_DELAY1 (0x2C / 4) +#define R_FMT (0x40 / 4) +#define R_TXDATA (0x48 / 4) +#define R_RXDATA (0x4C / 4) +#define R_TXMARK (0x50 / 4) +#define R_RXMARK (0x54 / 4) +#define R_FCTRL (0x60 / 4) +#define R_FFMT (0x64 / 4) +#define R_IE (0x70 / 4) +#define R_IP (0x74 / 4) + +#define FMT_DIR (1 << 3) + +#define TXDATA_FULL (1 << 31) +#define RXDATA_EMPTY (1 << 31) + +#define IE_TXWM (1 << 0) +#define IE_RXWM (1 << 1) + +#define IP_TXWM (1 << 0) +#define IP_RXWM (1 << 1) + +#define FIFO_CAPACITY 8 + +static void sifive_spi_txfifo_reset(SiFiveSPIState *s) +{ + fifo8_reset(&s->tx_fifo); + + s->regs[R_TXDATA] &= ~TXDATA_FULL; + s->regs[R_IP] &= ~IP_TXWM; +} + +static void sifive_spi_rxfifo_reset(SiFiveSPIState *s) +{ + fifo8_reset(&s->rx_fifo); + + s->regs[R_RXDATA] |= RXDATA_EMPTY; + s->regs[R_IP] &= ~IP_RXWM; +} + +static void sifive_spi_update_cs(SiFiveSPIState *s) +{ + int i; + + for (i = 0; i < s->num_cs; i++) { + if (s->regs[R_CSDEF] & (1 << i)) { + qemu_set_irq(s->cs_lines[i], !(s->regs[R_CSMODE])); + } + } +} + +static void sifive_spi_update_irq(SiFiveSPIState *s) +{ + int level; + + if (fifo8_num_used(&s->tx_fifo) < s->regs[R_TXMARK]) { + s->regs[R_IP] |= IP_TXWM; + } else { + s->regs[R_IP] &= ~IP_TXWM; + } + + if (fifo8_num_used(&s->rx_fifo) > s->regs[R_RXMARK]) { + s->regs[R_IP] |= IP_RXWM; + } else { + s->regs[R_IP] &= ~IP_RXWM; + } + + level = s->regs[R_IP] & s->regs[R_IE] ? 1 : 0; + qemu_set_irq(s->irq, level); +} + +static void sifive_spi_reset(DeviceState *d) +{ + SiFiveSPIState *s = SIFIVE_SPI(d); + + memset(s->regs, 0, sizeof(s->regs)); + + /* The reset value is high for all implemented CS pins */ + s->regs[R_CSDEF] = (1 << s->num_cs) - 1; + + /* Populate register with their default value */ + s->regs[R_SCKDIV] = 0x03; + s->regs[R_DELAY0] = 0x1001; + s->regs[R_DELAY1] = 0x01; + + sifive_spi_txfifo_reset(s); + sifive_spi_rxfifo_reset(s); + + sifive_spi_update_cs(s); + sifive_spi_update_irq(s); +} + +static void sifive_spi_flush_txfifo(SiFiveSPIState *s) +{ + uint8_t tx; + uint8_t rx; + + while (!fifo8_is_empty(&s->tx_fifo)) { + tx = fifo8_pop(&s->tx_fifo); + rx = ssi_transfer(s->spi, tx); + + if (!fifo8_is_full(&s->rx_fifo)) { + if (!(s->regs[R_FMT] & FMT_DIR)) { + fifo8_push(&s->rx_fifo, rx); + } + } + } +} + +static bool sifive_spi_is_bad_reg(hwaddr addr, bool allow_reserved) +{ + bool bad; + + switch (addr) { + /* reserved offsets */ + case 0x08: + case 0x0C: + case 0x1C: + case 0x20: + case 0x24: + case 0x30: + case 0x34: + case 0x38: + case 0x3C: + case 0x44: + case 0x58: + case 0x5C: + case 0x68: + case 0x6C: + bad = allow_reserved ? false : true; + break; + default: + bad = false; + } + + if (addr >= (SIFIVE_SPI_REG_NUM << 2)) { + bad = true; + } + + return bad; +} + +static uint64_t sifive_spi_read(void *opaque, hwaddr addr, unsigned int size) +{ + SiFiveSPIState *s = opaque; + uint32_t r; + + if (sifive_spi_is_bad_reg(addr, true)) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: bad read at address 0x%" + HWADDR_PRIx "\n", __func__, addr); + return 0; + } + + addr >>= 2; + switch (addr) { + case R_TXDATA: + if (fifo8_is_full(&s->tx_fifo)) { + return TXDATA_FULL; + } + r = 0; + break; + + case R_RXDATA: + if (fifo8_is_empty(&s->rx_fifo)) { + return RXDATA_EMPTY; + } + r = fifo8_pop(&s->rx_fifo); + break; + + default: + r = s->regs[addr]; + break; + } + + sifive_spi_update_irq(s); + + return r; +} + +static void sifive_spi_write(void *opaque, hwaddr addr, + uint64_t val64, unsigned int size) +{ + SiFiveSPIState *s = opaque; + uint32_t value = val64; + + if (sifive_spi_is_bad_reg(addr, false)) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: bad write at addr=0x%" + HWADDR_PRIx " value=0x%x\n", __func__, addr, value); + return; + } + + addr >>= 2; + switch (addr) { + case R_CSID: + if (value >= s->num_cs) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid csid %d\n", + __func__, value); + } else { + s->regs[R_CSID] = value; + sifive_spi_update_cs(s); + } + break; + + case R_CSDEF: + if (value >= (1 << s->num_cs)) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid csdef %x\n", + __func__, value); + } else { + s->regs[R_CSDEF] = value; + } + break; + + case R_CSMODE: + if (value > 3) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid csmode %x\n", + __func__, value); + } else { + s->regs[R_CSMODE] = value; + sifive_spi_update_cs(s); + } + break; + + case R_TXDATA: + if (!fifo8_is_full(&s->tx_fifo)) { + fifo8_push(&s->tx_fifo, (uint8_t)value); + sifive_spi_flush_txfifo(s); + } + break; + + case R_RXDATA: + case R_IP: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: invalid write to read-only reigster 0x%" + HWADDR_PRIx " with 0x%x\n", __func__, addr << 2, value); + break; + + case R_TXMARK: + case R_RXMARK: + if (value >= FIFO_CAPACITY) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid watermark %d\n", + __func__, value); + } else { + s->regs[addr] = value; + } + break; + + case R_FCTRL: + case R_FFMT: + qemu_log_mask(LOG_UNIMP, + "%s: direct-map flash interface unimplemented\n", + __func__); + break; + + default: + s->regs[addr] = value; + break; + } + + sifive_spi_update_irq(s); +} + +static const MemoryRegionOps sifive_spi_ops = { + .read = sifive_spi_read, + .write = sifive_spi_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4 + } +}; + +static void sifive_spi_realize(DeviceState *dev, Error **errp) +{ + SysBusDevice *sbd = SYS_BUS_DEVICE(dev); + SiFiveSPIState *s = SIFIVE_SPI(dev); + int i; + + s->spi = ssi_create_bus(dev, "spi"); + sysbus_init_irq(sbd, &s->irq); + + s->cs_lines = g_new0(qemu_irq, s->num_cs); + for (i = 0; i < s->num_cs; i++) { + sysbus_init_irq(sbd, &s->cs_lines[i]); + } + + memory_region_init_io(&s->mmio, OBJECT(s), &sifive_spi_ops, s, + TYPE_SIFIVE_SPI, 0x1000); + sysbus_init_mmio(sbd, &s->mmio); + + fifo8_create(&s->tx_fifo, FIFO_CAPACITY); + fifo8_create(&s->rx_fifo, FIFO_CAPACITY); +} + +static Property sifive_spi_properties[] = { + DEFINE_PROP_UINT32("num-cs", SiFiveSPIState, num_cs, 1), + DEFINE_PROP_END_OF_LIST(), +}; + +static void sifive_spi_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + device_class_set_props(dc, sifive_spi_properties); + dc->reset = sifive_spi_reset; + dc->realize = sifive_spi_realize; +} + +static const TypeInfo sifive_spi_info = { + .name = TYPE_SIFIVE_SPI, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(SiFiveSPIState), + .class_init = sifive_spi_class_init, +}; + +static void sifive_spi_register_types(void) +{ + type_register_static(&sifive_spi_info); +} + +type_init(sifive_spi_register_types) |