diff options
Diffstat (limited to 'hw/riscv/sifive_u.c')
-rw-r--r-- | hw/riscv/sifive_u.c | 102 |
1 files changed, 95 insertions, 7 deletions
diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c index 59b61ce..7b59942 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[] = { |