diff options
author | Peter Maydell | 2020-06-22 15:45:25 +0200 |
---|---|---|
committer | Peter Maydell | 2020-06-22 15:45:25 +0200 |
commit | 171199f56f5f9bdf1e5d670d09ef1351d8f01bae (patch) | |
tree | ae6aa5c52b0fffc75fef82f2cc99afe7f7d3ac99 /hw/riscv/sifive_u.c | |
parent | Merge remote-tracking branch 'remotes/kraxel/tags/audio-20200619-pull-request... (diff) | |
parent | hw/riscv: sifive_u: Add a dummy DDR memory controller device (diff) | |
download | qemu-171199f56f5f9bdf1e5d670d09ef1351d8f01bae.tar.gz qemu-171199f56f5f9bdf1e5d670d09ef1351d8f01bae.tar.xz qemu-171199f56f5f9bdf1e5d670d09ef1351d8f01bae.zip |
Merge remote-tracking branch 'remotes/alistair/tags/pull-riscv-to-apply-20200619-3' into staging
This is a range of patches for RISC-V.
Some key points are:
- Generalise the CPU init functions
- Support the SiFive revB machine
- Improvements to the Hypervisor implementation and error checking
- Connect some OpenTitan devices
- Changes to the sifive_u machine to support U-boot
v2:
- Fix missing realise assert
# gpg: Signature made Fri 19 Jun 2020 17:34:34 BST
# gpg: using RSA key F6C4AC46D4934868D3B8CE8F21E10D29DF977054
# gpg: Good signature from "Alistair Francis <alistair@alistair23.me>" [full]
# Primary key fingerprint: F6C4 AC46 D493 4868 D3B8 CE8F 21E1 0D29 DF97 7054
* remotes/alistair/tags/pull-riscv-to-apply-20200619-3: (32 commits)
hw/riscv: sifive_u: Add a dummy DDR memory controller device
hw/riscv: sifive_u: Sort the SoC memmap table entries
hw/riscv: sifive_u: Support different boot source per MSEL pin state
hw/riscv: sifive: Change SiFive E/U CPU reset vector to 0x1004
target/riscv: Rename IBEX CPU init routine
hw/riscv: sifive_u: Add a new property msel for MSEL pin state
hw/riscv: sifive_u: Rename serial property get/set functions to a generic name
hw/riscv: sifive_u: Add reset functionality
hw/riscv: sifive_gpio: Do not blindly trigger output IRQs
hw/riscv: sifive_u: Hook a GPIO controller
hw/riscv: sifive_gpio: Add a new 'ngpio' property
hw/riscv: sifive_gpio: Clean up the codes
hw/riscv: sifive_u: Generate device tree node for OTP
hw/riscv: sifive_u: Simplify the GEM IRQ connect code a little bit
hw/riscv: opentitan: Remove the riscv_ prefix of the machine* and soc* functions
hw/riscv: sifive_e: Remove the riscv_ prefix of the machine* and soc* functions
target/riscv: Use a smaller guess size for no-MMU PMP
riscv/opentitan: Connect the UART device
riscv/opentitan: Connect the PLIC device
hw/intc: Initial commit of lowRISC Ibex PLIC
...
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw/riscv/sifive_u.c')
-rw-r--r-- | hw/riscv/sifive_u.c | 157 |
1 files changed, 130 insertions, 27 deletions
diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c index ea197ab64f..7d051e7c92 100644 --- a/hw/riscv/sifive_u.c +++ b/hw/riscv/sifive_u.c @@ -11,8 +11,9 @@ * 1) CLINT (Core Level Interruptor) * 2) PLIC (Platform Level Interrupt Controller) * 3) PRCI (Power, Reset, Clock, Interrupt) - * 4) OTP (One-Time Programmable) memory with stored serial number - * 5) GEM (Gigabit Ethernet Controller) and management block + * 4) GPIO (General Purpose Input/Output Controller) + * 5) OTP (One-Time Programmable) memory with stored serial number + * 6) GEM (Gigabit Ethernet Controller) and management block * * This board currently generates devicetree dynamically that indicates at least * two harts and up to five harts. @@ -36,6 +37,7 @@ #include "qapi/error.h" #include "qapi/visitor.h" #include "hw/boards.h" +#include "hw/irq.h" #include "hw/loader.h" #include "hw/sysbus.h" #include "hw/char/serial.h" @@ -52,6 +54,7 @@ #include "net/eth.h" #include "sysemu/arch_init.h" #include "sysemu/device_tree.h" +#include "sysemu/runstate.h" #include "sysemu/sysemu.h" #include "exec/address-spaces.h" @@ -75,11 +78,13 @@ static const struct MemmapEntry { [SIFIVE_U_PRCI] = { 0x10000000, 0x1000 }, [SIFIVE_U_UART0] = { 0x10010000, 0x1000 }, [SIFIVE_U_UART1] = { 0x10011000, 0x1000 }, + [SIFIVE_U_GPIO] = { 0x10060000, 0x1000 }, [SIFIVE_U_OTP] = { 0x10070000, 0x1000 }, - [SIFIVE_U_FLASH0] = { 0x20000000, 0x10000000 }, - [SIFIVE_U_DRAM] = { 0x80000000, 0x0 }, [SIFIVE_U_GEM] = { 0x10090000, 0x2000 }, [SIFIVE_U_GEM_MGMT] = { 0x100a0000, 0x1000 }, + [SIFIVE_U_DMC] = { 0x100b0000, 0x10000 }, + [SIFIVE_U_FLASH0] = { 0x20000000, 0x10000000 }, + [SIFIVE_U_DRAM] = { 0x80000000, 0x0 }, }; #define OTP_SERIAL 1 @@ -94,7 +99,7 @@ static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap, uint32_t *cells; char *nodename; char ethclk_names[] = "pclk\0hclk"; - uint32_t plic_phandle, prci_phandle, phandle = 1; + uint32_t plic_phandle, prci_phandle, gpio_phandle, phandle = 1; uint32_t hfclk_phandle, rtcclk_phandle, phy_phandle; fdt = s->fdt = create_device_tree(&s->fdt_size); @@ -207,6 +212,17 @@ static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap, g_free(cells); g_free(nodename); + nodename = g_strdup_printf("/soc/otp@%lx", + (long)memmap[SIFIVE_U_OTP].base); + qemu_fdt_add_subnode(fdt, nodename); + qemu_fdt_setprop_cell(fdt, nodename, "fuse-count", SIFIVE_U_OTP_REG_SIZE); + qemu_fdt_setprop_cells(fdt, nodename, "reg", + 0x0, memmap[SIFIVE_U_OTP].base, + 0x0, memmap[SIFIVE_U_OTP].size); + qemu_fdt_setprop_string(fdt, nodename, "compatible", + "sifive,fu540-c000-otp"); + g_free(nodename); + prci_phandle = phandle++; nodename = g_strdup_printf("/soc/clock-controller@%lx", (long)memmap[SIFIVE_U_PRCI].base); @@ -257,6 +273,36 @@ static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap, g_free(cells); g_free(nodename); + gpio_phandle = phandle++; + nodename = g_strdup_printf("/soc/gpio@%lx", + (long)memmap[SIFIVE_U_GPIO].base); + qemu_fdt_add_subnode(fdt, nodename); + qemu_fdt_setprop_cell(fdt, nodename, "phandle", gpio_phandle); + qemu_fdt_setprop_cells(fdt, nodename, "clocks", + prci_phandle, PRCI_CLK_TLCLK); + qemu_fdt_setprop_cell(fdt, nodename, "#interrupt-cells", 2); + qemu_fdt_setprop(fdt, nodename, "interrupt-controller", NULL, 0); + qemu_fdt_setprop_cell(fdt, nodename, "#gpio-cells", 2); + qemu_fdt_setprop(fdt, nodename, "gpio-controller", NULL, 0); + qemu_fdt_setprop_cells(fdt, nodename, "reg", + 0x0, memmap[SIFIVE_U_GPIO].base, + 0x0, memmap[SIFIVE_U_GPIO].size); + qemu_fdt_setprop_cells(fdt, nodename, "interrupts", SIFIVE_U_GPIO_IRQ0, + SIFIVE_U_GPIO_IRQ1, SIFIVE_U_GPIO_IRQ2, SIFIVE_U_GPIO_IRQ3, + SIFIVE_U_GPIO_IRQ4, SIFIVE_U_GPIO_IRQ5, SIFIVE_U_GPIO_IRQ6, + SIFIVE_U_GPIO_IRQ7, SIFIVE_U_GPIO_IRQ8, SIFIVE_U_GPIO_IRQ9, + SIFIVE_U_GPIO_IRQ10, SIFIVE_U_GPIO_IRQ11, SIFIVE_U_GPIO_IRQ12, + SIFIVE_U_GPIO_IRQ13, SIFIVE_U_GPIO_IRQ14, SIFIVE_U_GPIO_IRQ15); + qemu_fdt_setprop_cell(fdt, nodename, "interrupt-parent", plic_phandle); + qemu_fdt_setprop_string(fdt, nodename, "compatible", "sifive,gpio0"); + g_free(nodename); + + nodename = g_strdup_printf("/gpio-restart"); + qemu_fdt_add_subnode(fdt, nodename); + qemu_fdt_setprop_cells(fdt, nodename, "gpios", gpio_phandle, 10, 1); + qemu_fdt_setprop_string(fdt, nodename, "compatible", "gpio-restart"); + g_free(nodename); + phy_phandle = phandle++; nodename = g_strdup_printf("/soc/ethernet@%lx", (long)memmap[SIFIVE_U_GEM].base); @@ -317,6 +363,14 @@ static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap, g_free(nodename); } +static void sifive_u_machine_reset(void *opaque, int n, int level) +{ + /* gpio pin active low triggers reset */ + if (!level) { + qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); + } +} + static void sifive_u_machine_init(MachineState *machine) { const struct MemmapEntry *memmap = sifive_u_memmap; @@ -345,11 +399,41 @@ static void sifive_u_machine_init(MachineState *machine) memory_region_add_subregion(system_memory, memmap[SIFIVE_U_FLASH0].base, flash0); + /* register gpio-restart */ + qdev_connect_gpio_out(DEVICE(&(s->soc.gpio)), 10, + qemu_allocate_irq(sifive_u_machine_reset, NULL, 0)); + /* create device tree */ create_fdt(s, memmap, machine->ram_size, machine->kernel_cmdline); - riscv_find_and_load_firmware(machine, BIOS_FILENAME, - memmap[SIFIVE_U_DRAM].base, NULL); + if (s->start_in_flash) { + /* + * If start_in_flash property is given, assign s->msel to a value + * that representing booting from QSPI0 memory-mapped flash. + * + * This also means that when both start_in_flash and msel properties + * are given, start_in_flash takes the precedence over msel. + * + * Note this is to keep backward compatibility not to break existing + * users that use start_in_flash property. + */ + s->msel = MSEL_MEMMAP_QSPI0_FLASH; + } + + switch (s->msel) { + case MSEL_MEMMAP_QSPI0_FLASH: + start_addr = memmap[SIFIVE_U_FLASH0].base; + break; + case MSEL_L2LIM_QSPI0_FLASH: + case MSEL_L2LIM_QSPI2_SD: + start_addr = memmap[SIFIVE_U_L2LIM].base; + break; + default: + start_addr = memmap[SIFIVE_U_DRAM].base; + break; + } + + riscv_find_and_load_firmware(machine, BIOS_FILENAME, start_addr, NULL); if (machine->kernel_filename) { uint64_t kernel_entry = riscv_load_kernel(machine->kernel_filename, @@ -367,24 +451,20 @@ static void sifive_u_machine_init(MachineState *machine) } } - if (s->start_in_flash) { - start_addr = memmap[SIFIVE_U_FLASH0].base; - } - /* reset vector */ uint32_t reset_vec[8] = { + s->msel, /* MSEL pin state */ 0x00000297, /* 1: auipc t0, %pcrel_hi(dtb) */ - 0x02028593, /* addi a1, t0, %pcrel_lo(1b) */ + 0x01c28593, /* addi a1, t0, %pcrel_lo(1b) */ 0xf1402573, /* csrr a0, mhartid */ #if defined(TARGET_RISCV32) 0x0182a283, /* lw t0, 24(t0) */ #elif defined(TARGET_RISCV64) - 0x0182b283, /* ld t0, 24(t0) */ + 0x0182e283, /* lwu t0, 24(t0) */ #endif 0x00028067, /* jr t0 */ 0x00000000, start_addr, /* start: .dword */ - 0x00000000, /* dtb: */ }; @@ -421,14 +501,16 @@ static void sifive_u_machine_set_start_in_flash(Object *obj, bool value, Error * s->start_in_flash = value; } -static void sifive_u_machine_get_serial(Object *obj, Visitor *v, const char *name, - void *opaque, Error **errp) +static void sifive_u_machine_get_uint32_prop(Object *obj, Visitor *v, + const char *name, void *opaque, + Error **errp) { visit_type_uint32(v, name, (uint32_t *)opaque, errp); } -static void sifive_u_machine_set_serial(Object *obj, Visitor *v, const char *name, - void *opaque, Error **errp) +static void sifive_u_machine_set_uint32_prop(Object *obj, Visitor *v, + const char *name, void *opaque, + Error **errp) { visit_type_uint32(v, name, (uint32_t *)opaque, errp); } @@ -443,12 +525,20 @@ static void sifive_u_machine_instance_init(Object *obj) sifive_u_machine_set_start_in_flash); object_property_set_description(obj, "start-in-flash", "Set on to tell QEMU's ROM to jump to " - "flash. Otherwise QEMU will jump to DRAM"); + "flash. Otherwise QEMU will jump to DRAM " + "or L2LIM depending on the msel value"); + + s->msel = 0; + object_property_add(obj, "msel", "uint32", + sifive_u_machine_get_uint32_prop, + sifive_u_machine_set_uint32_prop, NULL, &s->msel); + object_property_set_description(obj, "msel", + "Mode Select (MSEL[3:0]) pin state"); s->serial = OTP_SERIAL; object_property_add(obj, "serial", "uint32", - sifive_u_machine_get_serial, - sifive_u_machine_set_serial, NULL, &s->serial); + sifive_u_machine_get_uint32_prop, + sifive_u_machine_set_uint32_prop, NULL, &s->serial); object_property_set_description(obj, "serial", "Board serial number"); } @@ -504,6 +594,7 @@ static void sifive_u_soc_instance_init(Object *obj) object_initialize_child(obj, "prci", &s->prci, TYPE_SIFIVE_U_PRCI); object_initialize_child(obj, "otp", &s->otp, TYPE_SIFIVE_U_OTP); object_initialize_child(obj, "gem", &s->gem, TYPE_CADENCE_GEM); + object_initialize_child(obj, "gpio", &s->gpio, TYPE_SIFIVE_GPIO); } static void sifive_u_soc_realize(DeviceState *dev, Error **errp) @@ -514,7 +605,6 @@ static void sifive_u_soc_realize(DeviceState *dev, Error **errp) MemoryRegion *system_memory = get_system_memory(); MemoryRegion *mask_rom = g_new(MemoryRegion, 1); MemoryRegion *l2lim_mem = g_new(MemoryRegion, 1); - qemu_irq plic_gpios[SIFIVE_U_PLIC_NUM_SOURCES]; char *plic_hart_config; size_t plic_hart_config_len; int i; @@ -590,14 +680,24 @@ static void sifive_u_soc_realize(DeviceState *dev, Error **errp) sysbus_realize(SYS_BUS_DEVICE(&s->prci), &err); sysbus_mmio_map(SYS_BUS_DEVICE(&s->prci), 0, memmap[SIFIVE_U_PRCI].base); + qdev_prop_set_uint32(DEVICE(&s->gpio), "ngpio", 16); + sysbus_realize(SYS_BUS_DEVICE(&s->gpio), &err); + sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpio), 0, memmap[SIFIVE_U_GPIO].base); + + /* Pass all GPIOs to the SOC layer so they are available to the board */ + qdev_pass_gpios(DEVICE(&s->gpio), dev, NULL); + + /* Connect GPIO interrupts to the PLIC */ + for (i = 0; i < 16; i++) { + sysbus_connect_irq(SYS_BUS_DEVICE(&s->gpio), i, + qdev_get_gpio_in(DEVICE(s->plic), + SIFIVE_U_GPIO_IRQ0 + i)); + } + qdev_prop_set_uint32(DEVICE(&s->otp), "serial", s->serial); sysbus_realize(SYS_BUS_DEVICE(&s->otp), &err); sysbus_mmio_map(SYS_BUS_DEVICE(&s->otp), 0, memmap[SIFIVE_U_OTP].base); - for (i = 0; i < SIFIVE_U_PLIC_NUM_SOURCES; i++) { - plic_gpios[i] = qdev_get_gpio_in(DEVICE(s->plic), i); - } - if (nd->used) { qemu_check_nic_model(nd, TYPE_CADENCE_GEM); qdev_set_nic_properties(DEVICE(&s->gem), nd); @@ -611,10 +711,13 @@ static void sifive_u_soc_realize(DeviceState *dev, Error **errp) } sysbus_mmio_map(SYS_BUS_DEVICE(&s->gem), 0, memmap[SIFIVE_U_GEM].base); sysbus_connect_irq(SYS_BUS_DEVICE(&s->gem), 0, - plic_gpios[SIFIVE_U_GEM_IRQ]); + qdev_get_gpio_in(DEVICE(s->plic), SIFIVE_U_GEM_IRQ)); create_unimplemented_device("riscv.sifive.u.gem-mgmt", memmap[SIFIVE_U_GEM_MGMT].base, memmap[SIFIVE_U_GEM_MGMT].size); + + create_unimplemented_device("riscv.sifive.u.dmc", + memmap[SIFIVE_U_DMC].base, memmap[SIFIVE_U_DMC].size); } static Property sifive_u_soc_props[] = { |