diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2019-09-19 11:14:28 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2019-09-19 11:14:28 +0100 |
commit | 7cc0cdcd6a771010ca4a4857c4e4df966bb4e6c2 (patch) | |
tree | 827153abeccb777659902d1546fe3c22e52d7d92 /hw | |
parent | f39641125996550b76f9ebbfe03430aecc6473c4 (diff) | |
parent | b3e86929189c526d22ef49e18f2f5066535f6deb (diff) |
Merge remote-tracking branch 'remotes/palmer/tags/riscv-for-master-4.2-sf1-v3' into staging
RISC-V Patches for the 4.2 Soft Freeze, Part 1, v3
This contains quite a few patches that I'd like to target for 4.2.
They're mostly emulation fixes for the sifive_u board, which now much
more closely matches the hardware and can therefor run the same fireware
as what gets loaded onto the board. Additional user-visible
improvements include:
* support for loading initrd files from the command line into Linux, via
/chosen/linux,initrd-{start,end} device tree nodes.
* The conversion of LOG_TRACE to trace events.
* The addition of clock DT nodes for our uart and ethernet.
This also includes some preliminary work for the H extension patches,
but does not include the H extension patches as I haven't had time to
review them yet.
This passes my OE boot test on 32-bit and 64-bit virt machines, as well
as a 64-bit upstream Linux boot on the sifive_u machine. It has been
fixed to actually pass "make check" this time.
Changes since v2 (never made it to the list):
* Sets the sifive_u machine default core count to 2 instead of 5.
Changes since v1 <20190910190513.21160-1-palmer@sifive.com>:
* Sets the sifive_u machine default core count to 5 instead of 1, as
it's impossible to have a single core sifive_u machine.
# gpg: Signature made Tue 17 Sep 2019 16:43:30 BST
# gpg: using RSA key 00CE76D1834960DFCE886DF8EF4CA1502CCBAB41
# gpg: issuer "palmer@dabbelt.com"
# gpg: Good signature from "Palmer Dabbelt <palmer@dabbelt.com>" [unknown]
# gpg: aka "Palmer Dabbelt <palmer@sifive.com>" [unknown]
# gpg: WARNING: This key is not certified with a trusted signature!
# gpg: There is no indication that the signature belongs to the owner.
# Primary key fingerprint: 00CE 76D1 8349 60DF CE88 6DF8 EF4C A150 2CCB AB41
* remotes/palmer/tags/riscv-for-master-4.2-sf1-v3: (48 commits)
gdbstub: riscv: fix the fflags registers
target/riscv: Use TB_FLAGS_MSTATUS_FS for floating point
target/riscv: Fix mstatus dirty mask
target/riscv: Use both register name and ABI name
riscv: sifive_u: Update model and compatible strings in device tree
riscv: sifive_u: Remove handcrafted clock nodes for UART and ethernet
riscv: sifive_u: Fix broken GEM support
riscv: sifive_u: Instantiate OTP memory with a serial number
riscv: sifive: Implement a model for SiFive FU540 OTP
riscv: roms: Update default bios for sifive_u machine
riscv: sifive_u: Change UART node name in device tree
riscv: sifive_u: Update UART base addresses and IRQs
riscv: sifive_u: Reference PRCI clocks in UART and ethernet nodes
riscv: sifive_u: Add PRCI block to the SoC
riscv: sifive_u: Generate hfclk and rtcclk nodes
riscv: sifive: Implement PRCI model for FU540
riscv: sifive_u: Update PLIC hart topology configuration string
riscv: sifive_u: Update hart configuration to reflect the real FU540 SoC
riscv: sifive_u: Set the minimum number of cpus to 2
riscv: hart: Add a "hartid-base" property to RISC-V hart array
...
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw')
-rw-r--r-- | hw/riscv/Kconfig | 2 | ||||
-rw-r--r-- | hw/riscv/Makefile.objs | 4 | ||||
-rw-r--r-- | hw/riscv/boot.c | 26 | ||||
-rw-r--r-- | hw/riscv/riscv_hart.c | 34 | ||||
-rw-r--r-- | hw/riscv/sifive_e.c | 27 | ||||
-rw-r--r-- | hw/riscv/sifive_e_prci.c | 124 | ||||
-rw-r--r-- | hw/riscv/sifive_plic.c | 12 | ||||
-rw-r--r-- | hw/riscv/sifive_prci.c | 125 | ||||
-rw-r--r-- | hw/riscv/sifive_test.c | 11 | ||||
-rw-r--r-- | hw/riscv/sifive_u.c | 253 | ||||
-rw-r--r-- | hw/riscv/sifive_u_otp.c | 191 | ||||
-rw-r--r-- | hw/riscv/sifive_u_prci.c | 169 | ||||
-rw-r--r-- | hw/riscv/sifive_uart.c | 10 | ||||
-rw-r--r-- | hw/riscv/spike.c | 1 | ||||
-rw-r--r-- | hw/riscv/virt.c | 40 |
15 files changed, 749 insertions, 280 deletions
diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig index 8674211085..fb19b2df3a 100644 --- a/hw/riscv/Kconfig +++ b/hw/riscv/Kconfig @@ -12,12 +12,14 @@ config SIFIVE_E bool select HART select SIFIVE + select UNIMP config SIFIVE_U bool select CADENCE select HART select SIFIVE + select UNIMP config SPIKE bool diff --git a/hw/riscv/Makefile.objs b/hw/riscv/Makefile.objs index eb9d4f9ffc..fc3c6dd7c8 100644 --- a/hw/riscv/Makefile.objs +++ b/hw/riscv/Makefile.objs @@ -2,12 +2,14 @@ obj-y += boot.o obj-$(CONFIG_SPIKE) += riscv_htif.o obj-$(CONFIG_HART) += riscv_hart.o obj-$(CONFIG_SIFIVE_E) += sifive_e.o +obj-$(CONFIG_SIFIVE_E) += sifive_e_prci.o obj-$(CONFIG_SIFIVE) += sifive_clint.o obj-$(CONFIG_SIFIVE) += sifive_gpio.o -obj-$(CONFIG_SIFIVE) += sifive_prci.o obj-$(CONFIG_SIFIVE) += sifive_plic.o obj-$(CONFIG_SIFIVE) += sifive_test.o obj-$(CONFIG_SIFIVE_U) += sifive_u.o +obj-$(CONFIG_SIFIVE_U) += sifive_u_otp.o +obj-$(CONFIG_SIFIVE_U) += sifive_u_prci.o obj-$(CONFIG_SIFIVE) += sifive_uart.o obj-$(CONFIG_SPIKE) += spike.o obj-$(CONFIG_RISCV_VIRT) += virt.o diff --git a/hw/riscv/boot.c b/hw/riscv/boot.c index 4c63b5cf8a..2e92fb0680 100644 --- a/hw/riscv/boot.c +++ b/hw/riscv/boot.c @@ -69,25 +69,33 @@ void riscv_find_and_load_firmware(MachineState *machine, * so then in the future we can make "-bios default" the default option * if no -bios option is set without breaking anything. */ - firmware_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, - default_machine_firmware); - if (firmware_filename == NULL) { - error_report("Unable to load the default RISC-V firmware \"%s\"", - default_machine_firmware); - exit(1); - } + firmware_filename = riscv_find_firmware(default_machine_firmware); } else { firmware_filename = machine->firmware; + if (strcmp(firmware_filename, "none")) { + firmware_filename = riscv_find_firmware(firmware_filename); + } } if (strcmp(firmware_filename, "none")) { /* If not "none" load the firmware */ riscv_load_firmware(firmware_filename, firmware_load_addr); + g_free(firmware_filename); } +} - if (!strcmp(machine->firmware, "default")) { - g_free(firmware_filename); +char *riscv_find_firmware(const char *firmware_filename) +{ + char *filename; + + filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, firmware_filename); + if (filename == NULL) { + error_report("Unable to load the RISC-V firmware \"%s\"", + firmware_filename); + exit(1); } + + return filename; } target_ulong riscv_load_firmware(const char *firmware_filename, diff --git a/hw/riscv/riscv_hart.c b/hw/riscv/riscv_hart.c index d0f3199968..5b98227db6 100644 --- a/hw/riscv/riscv_hart.c +++ b/hw/riscv/riscv_hart.c @@ -3,7 +3,7 @@ * * Copyright (c) 2017 SiFive, Inc. * - * Holds the state of a heterogenous array of RISC-V harts + * Holds the state of a homogeneous array of RISC-V harts * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -29,6 +29,7 @@ static Property riscv_harts_props[] = { DEFINE_PROP_UINT32("num-harts", RISCVHartArrayState, num_harts, 1), + DEFINE_PROP_UINT32("hartid-base", RISCVHartArrayState, hartid_base, 0), DEFINE_PROP_STRING("cpu-type", RISCVHartArrayState, cpu_type), DEFINE_PROP_END_OF_LIST(), }; @@ -39,26 +40,33 @@ static void riscv_harts_cpu_reset(void *opaque) cpu_reset(CPU(cpu)); } +static void riscv_hart_realize(RISCVHartArrayState *s, int idx, + char *cpu_type, Error **errp) +{ + Error *err = NULL; + + object_initialize_child(OBJECT(s), "harts[*]", &s->harts[idx], + sizeof(RISCVCPU), cpu_type, + &error_abort, NULL); + s->harts[idx].env.mhartid = s->hartid_base + idx; + qemu_register_reset(riscv_harts_cpu_reset, &s->harts[idx]); + object_property_set_bool(OBJECT(&s->harts[idx]), true, + "realized", &err); + if (err) { + error_propagate(errp, err); + return; + } +} + static void riscv_harts_realize(DeviceState *dev, Error **errp) { RISCVHartArrayState *s = RISCV_HART_ARRAY(dev); - Error *err = NULL; int n; s->harts = g_new0(RISCVCPU, s->num_harts); for (n = 0; n < s->num_harts; n++) { - object_initialize_child(OBJECT(s), "harts[*]", &s->harts[n], - sizeof(RISCVCPU), s->cpu_type, - &error_abort, NULL); - s->harts[n].env.mhartid = n; - qemu_register_reset(riscv_harts_cpu_reset, &s->harts[n]); - object_property_set_bool(OBJECT(&s->harts[n]), true, - "realized", &err); - if (err) { - error_propagate(errp, err); - return; - } + riscv_hart_realize(s, n, s->cpu_type, errp); } } diff --git a/hw/riscv/sifive_e.c b/hw/riscv/sifive_e.c index 792d75a1a3..0f9d641a0e 100644 --- a/hw/riscv/sifive_e.c +++ b/hw/riscv/sifive_e.c @@ -36,13 +36,14 @@ #include "hw/loader.h" #include "hw/sysbus.h" #include "hw/char/serial.h" +#include "hw/misc/unimp.h" #include "target/riscv/cpu.h" #include "hw/riscv/riscv_hart.h" #include "hw/riscv/sifive_plic.h" #include "hw/riscv/sifive_clint.h" -#include "hw/riscv/sifive_prci.h" #include "hw/riscv/sifive_uart.h" #include "hw/riscv/sifive_e.h" +#include "hw/riscv/sifive_e_prci.h" #include "hw/riscv/boot.h" #include "chardev/char.h" #include "sysemu/arch_init.h" @@ -74,14 +75,6 @@ static const struct MemmapEntry { [SIFIVE_E_DTIM] = { 0x80000000, 0x4000 } }; -static void sifive_mmio_emulate(MemoryRegion *parent, const char *name, - uintptr_t offset, uintptr_t length) -{ - MemoryRegion *mock_mmio = g_new(MemoryRegion, 1); - memory_region_init_ram(mock_mmio, NULL, name, length, &error_fatal); - memory_region_add_subregion(parent, offset, mock_mmio); -} - static void riscv_sifive_e_init(MachineState *machine) { const struct MemmapEntry *memmap = sifive_e_memmap; @@ -172,9 +165,9 @@ static void riscv_sifive_e_soc_realize(DeviceState *dev, Error **errp) sifive_clint_create(memmap[SIFIVE_E_CLINT].base, memmap[SIFIVE_E_CLINT].size, ms->smp.cpus, SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE); - sifive_mmio_emulate(sys_mem, "riscv.sifive.e.aon", + create_unimplemented_device("riscv.sifive.e.aon", memmap[SIFIVE_E_AON].base, memmap[SIFIVE_E_AON].size); - sifive_prci_create(memmap[SIFIVE_E_PRCI].base); + sifive_e_prci_create(memmap[SIFIVE_E_PRCI].base); /* GPIO */ @@ -199,19 +192,19 @@ static void riscv_sifive_e_soc_realize(DeviceState *dev, Error **errp) sifive_uart_create(sys_mem, memmap[SIFIVE_E_UART0].base, serial_hd(0), qdev_get_gpio_in(DEVICE(s->plic), SIFIVE_E_UART0_IRQ)); - sifive_mmio_emulate(sys_mem, "riscv.sifive.e.qspi0", + create_unimplemented_device("riscv.sifive.e.qspi0", memmap[SIFIVE_E_QSPI0].base, memmap[SIFIVE_E_QSPI0].size); - sifive_mmio_emulate(sys_mem, "riscv.sifive.e.pwm0", + create_unimplemented_device("riscv.sifive.e.pwm0", memmap[SIFIVE_E_PWM0].base, memmap[SIFIVE_E_PWM0].size); sifive_uart_create(sys_mem, memmap[SIFIVE_E_UART1].base, serial_hd(1), qdev_get_gpio_in(DEVICE(s->plic), SIFIVE_E_UART1_IRQ)); - sifive_mmio_emulate(sys_mem, "riscv.sifive.e.qspi1", + create_unimplemented_device("riscv.sifive.e.qspi1", memmap[SIFIVE_E_QSPI1].base, memmap[SIFIVE_E_QSPI1].size); - sifive_mmio_emulate(sys_mem, "riscv.sifive.e.pwm1", + create_unimplemented_device("riscv.sifive.e.pwm1", memmap[SIFIVE_E_PWM1].base, memmap[SIFIVE_E_PWM1].size); - sifive_mmio_emulate(sys_mem, "riscv.sifive.e.qspi2", + create_unimplemented_device("riscv.sifive.e.qspi2", memmap[SIFIVE_E_QSPI2].base, memmap[SIFIVE_E_QSPI2].size); - sifive_mmio_emulate(sys_mem, "riscv.sifive.e.pwm2", + create_unimplemented_device("riscv.sifive.e.pwm2", memmap[SIFIVE_E_PWM2].base, memmap[SIFIVE_E_PWM2].size); /* Flash memory */ diff --git a/hw/riscv/sifive_e_prci.c b/hw/riscv/sifive_e_prci.c new file mode 100644 index 0000000000..a1c0d44f18 --- /dev/null +++ b/hw/riscv/sifive_e_prci.c @@ -0,0 +1,124 @@ +/* + * QEMU SiFive E PRCI (Power, Reset, Clock, Interrupt) + * + * Copyright (c) 2017 SiFive, Inc. + * + * Simple model of the PRCI to emulate register reads made by the SDK BSP + * + * 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/sysbus.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "hw/hw.h" +#include "hw/riscv/sifive_e_prci.h" + +static uint64_t sifive_e_prci_read(void *opaque, hwaddr addr, unsigned int size) +{ + SiFiveEPRCIState *s = opaque; + switch (addr) { + case SIFIVE_E_PRCI_HFROSCCFG: + return s->hfrosccfg; + case SIFIVE_E_PRCI_HFXOSCCFG: + return s->hfxosccfg; + case SIFIVE_E_PRCI_PLLCFG: + return s->pllcfg; + case SIFIVE_E_PRCI_PLLOUTDIV: + return s->plloutdiv; + } + qemu_log_mask(LOG_GUEST_ERROR, "%s: read: addr=0x%x\n", + __func__, (int)addr); + return 0; +} + +static void sifive_e_prci_write(void *opaque, hwaddr addr, + uint64_t val64, unsigned int size) +{ + SiFiveEPRCIState *s = opaque; + switch (addr) { + case SIFIVE_E_PRCI_HFROSCCFG: + s->hfrosccfg = (uint32_t) val64; + /* OSC stays ready */ + s->hfrosccfg |= SIFIVE_E_PRCI_HFROSCCFG_RDY; + break; + case SIFIVE_E_PRCI_HFXOSCCFG: + s->hfxosccfg = (uint32_t) val64; + /* OSC stays ready */ + s->hfxosccfg |= SIFIVE_E_PRCI_HFXOSCCFG_RDY; + break; + case SIFIVE_E_PRCI_PLLCFG: + s->pllcfg = (uint32_t) val64; + /* PLL stays locked */ + s->pllcfg |= SIFIVE_E_PRCI_PLLCFG_LOCK; + break; + case SIFIVE_E_PRCI_PLLOUTDIV: + s->plloutdiv = (uint32_t) val64; + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, "%s: bad write: addr=0x%x v=0x%x\n", + __func__, (int)addr, (int)val64); + } +} + +static const MemoryRegionOps sifive_e_prci_ops = { + .read = sifive_e_prci_read, + .write = sifive_e_prci_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4 + } +}; + +static void sifive_e_prci_init(Object *obj) +{ + SiFiveEPRCIState *s = SIFIVE_E_PRCI(obj); + + memory_region_init_io(&s->mmio, obj, &sifive_e_prci_ops, s, + TYPE_SIFIVE_E_PRCI, SIFIVE_E_PRCI_REG_SIZE); + sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio); + + s->hfrosccfg = (SIFIVE_E_PRCI_HFROSCCFG_RDY | SIFIVE_E_PRCI_HFROSCCFG_EN); + s->hfxosccfg = (SIFIVE_E_PRCI_HFXOSCCFG_RDY | SIFIVE_E_PRCI_HFXOSCCFG_EN); + s->pllcfg = (SIFIVE_E_PRCI_PLLCFG_REFSEL | SIFIVE_E_PRCI_PLLCFG_BYPASS | + SIFIVE_E_PRCI_PLLCFG_LOCK); + s->plloutdiv = SIFIVE_E_PRCI_PLLOUTDIV_DIV1; +} + +static const TypeInfo sifive_e_prci_info = { + .name = TYPE_SIFIVE_E_PRCI, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(SiFiveEPRCIState), + .instance_init = sifive_e_prci_init, +}; + +static void sifive_e_prci_register_types(void) +{ + type_register_static(&sifive_e_prci_info); +} + +type_init(sifive_e_prci_register_types) + + +/* + * Create PRCI device. + */ +DeviceState *sifive_e_prci_create(hwaddr addr) +{ + DeviceState *dev = qdev_create(NULL, TYPE_SIFIVE_E_PRCI); + qdev_init_nofail(dev); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr); + return dev; +} diff --git a/hw/riscv/sifive_plic.c b/hw/riscv/sifive_plic.c index 64a1a10380..98e4304b66 100644 --- a/hw/riscv/sifive_plic.c +++ b/hw/riscv/sifive_plic.c @@ -162,18 +162,6 @@ static void sifive_plic_update(SiFivePLICState *plic) } } -void sifive_plic_raise_irq(SiFivePLICState *plic, uint32_t irq) -{ - sifive_plic_set_pending(plic, irq, true); - sifive_plic_update(plic); -} - -void sifive_plic_lower_irq(SiFivePLICState *plic, uint32_t irq) -{ - sifive_plic_set_pending(plic, irq, false); - sifive_plic_update(plic); -} - static uint32_t sifive_plic_claim(SiFivePLICState *plic, uint32_t addrid) { int i, j; diff --git a/hw/riscv/sifive_prci.c b/hw/riscv/sifive_prci.c deleted file mode 100644 index 9837b6166f..0000000000 --- a/hw/riscv/sifive_prci.c +++ /dev/null @@ -1,125 +0,0 @@ -/* - * QEMU SiFive PRCI (Power, Reset, Clock, Interrupt) - * - * Copyright (c) 2017 SiFive, Inc. - * - * Simple model of the PRCI to emulate register reads made by the SDK BSP - * - * 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/hw.h" -#include "hw/sysbus.h" -#include "qemu/module.h" -#include "target/riscv/cpu.h" -#include "hw/hw.h" -#include "hw/riscv/sifive_prci.h" - -static uint64_t sifive_prci_read(void *opaque, hwaddr addr, unsigned int size) -{ - SiFivePRCIState *s = opaque; - switch (addr) { - case SIFIVE_PRCI_HFROSCCFG: - return s->hfrosccfg; - case SIFIVE_PRCI_HFXOSCCFG: - return s->hfxosccfg; - case SIFIVE_PRCI_PLLCFG: - return s->pllcfg; - case SIFIVE_PRCI_PLLOUTDIV: - return s->plloutdiv; - } - hw_error("%s: read: addr=0x%x\n", __func__, (int)addr); - return 0; -} - -static void sifive_prci_write(void *opaque, hwaddr addr, - uint64_t val64, unsigned int size) -{ - SiFivePRCIState *s = opaque; - switch (addr) { - case SIFIVE_PRCI_HFROSCCFG: - s->hfrosccfg = (uint32_t) val64; - /* OSC stays ready */ - s->hfrosccfg |= SIFIVE_PRCI_HFROSCCFG_RDY; - break; - case SIFIVE_PRCI_HFXOSCCFG: - s->hfxosccfg = (uint32_t) val64; - /* OSC stays ready */ - s->hfxosccfg |= SIFIVE_PRCI_HFXOSCCFG_RDY; - break; - case SIFIVE_PRCI_PLLCFG: - s->pllcfg = (uint32_t) val64; - /* PLL stays locked */ - s->pllcfg |= SIFIVE_PRCI_PLLCFG_LOCK; - break; - case SIFIVE_PRCI_PLLOUTDIV: - s->plloutdiv = (uint32_t) val64; - break; - default: - hw_error("%s: bad write: addr=0x%x v=0x%x\n", - __func__, (int)addr, (int)val64); - } -} - -static const MemoryRegionOps sifive_prci_ops = { - .read = sifive_prci_read, - .write = sifive_prci_write, - .endianness = DEVICE_NATIVE_ENDIAN, - .valid = { - .min_access_size = 4, - .max_access_size = 4 - } -}; - -static void sifive_prci_init(Object *obj) -{ - SiFivePRCIState *s = SIFIVE_PRCI(obj); - - memory_region_init_io(&s->mmio, obj, &sifive_prci_ops, s, - TYPE_SIFIVE_PRCI, 0x8000); - sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio); - - s->hfrosccfg = (SIFIVE_PRCI_HFROSCCFG_RDY | SIFIVE_PRCI_HFROSCCFG_EN); - s->hfxosccfg = (SIFIVE_PRCI_HFROSCCFG_RDY | SIFIVE_PRCI_HFROSCCFG_EN); - s->pllcfg = (SIFIVE_PRCI_PLLCFG_REFSEL | SIFIVE_PRCI_PLLCFG_BYPASS | - SIFIVE_PRCI_PLLCFG_LOCK); - s->plloutdiv = SIFIVE_PRCI_PLLOUTDIV_DIV1; - -} - -static const TypeInfo sifive_prci_info = { - .name = TYPE_SIFIVE_PRCI, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(SiFivePRCIState), - .instance_init = sifive_prci_init, -}; - -static void sifive_prci_register_types(void) -{ - type_register_static(&sifive_prci_info); -} - -type_init(sifive_prci_register_types) - - -/* - * Create PRCI device. - */ -DeviceState *sifive_prci_create(hwaddr addr) -{ - DeviceState *dev = qdev_create(NULL, TYPE_SIFIVE_PRCI); - qdev_init_nofail(dev); - sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr); - return dev; -} diff --git a/hw/riscv/sifive_test.c b/hw/riscv/sifive_test.c index afbb3aaf34..339195c6ff 100644 --- a/hw/riscv/sifive_test.c +++ b/hw/riscv/sifive_test.c @@ -19,10 +19,10 @@ */ #include "qemu/osdep.h" -#include "hw/hw.h" #include "hw/sysbus.h" +#include "qemu/log.h" #include "qemu/module.h" -#include "target/riscv/cpu.h" +#include "sysemu/runstate.h" #include "hw/hw.h" #include "hw/riscv/sifive_test.h" @@ -42,12 +42,15 @@ static void sifive_test_write(void *opaque, hwaddr addr, exit(code); case FINISHER_PASS: exit(0); + case FINISHER_RESET: + qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); + return; default: break; } } - hw_error("%s: write: addr=0x%x val=0x%016" PRIx64 "\n", - __func__, (int)addr, val64); + qemu_log_mask(LOG_GUEST_ERROR, "%s: write: addr=0x%x val=0x%016" PRIx64 "\n", + __func__, (int)addr, val64); } static const MemoryRegionOps sifive_test_ops = { diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c index 9910fa6708..9f8e84bf2e 100644 --- a/hw/riscv/sifive_u.c +++ b/hw/riscv/sifive_u.c @@ -3,14 +3,19 @@ * * Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu * Copyright (c) 2017 SiFive, Inc. + * Copyright (c) 2019 Bin Meng <bmeng.cn@gmail.com> * * Provides a board compatible with the SiFive Freedom U SDK: * * 0) UART * 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 * - * This board currently uses a hardcoded devicetree that indicates one hart. + * This board currently generates devicetree dynamically that indicates at least + * two harts and up to five harts. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -33,15 +38,17 @@ #include "hw/loader.h" #include "hw/sysbus.h" #include "hw/char/serial.h" +#include "hw/cpu/cluster.h" +#include "hw/misc/unimp.h" #include "target/riscv/cpu.h" #include "hw/riscv/riscv_hart.h" #include "hw/riscv/sifive_plic.h" #include "hw/riscv/sifive_clint.h" #include "hw/riscv/sifive_uart.h" -#include "hw/riscv/sifive_prci.h" #include "hw/riscv/sifive_u.h" #include "hw/riscv/boot.h" #include "chardev/char.h" +#include "net/eth.h" #include "sysemu/arch_init.h" #include "sysemu/device_tree.h" #include "sysemu/sysemu.h" @@ -59,23 +66,29 @@ static const struct MemmapEntry { [SIFIVE_U_MROM] = { 0x1000, 0x11000 }, [SIFIVE_U_CLINT] = { 0x2000000, 0x10000 }, [SIFIVE_U_PLIC] = { 0xc000000, 0x4000000 }, - [SIFIVE_U_UART0] = { 0x10013000, 0x1000 }, - [SIFIVE_U_UART1] = { 0x10023000, 0x1000 }, + [SIFIVE_U_PRCI] = { 0x10000000, 0x1000 }, + [SIFIVE_U_UART0] = { 0x10010000, 0x1000 }, + [SIFIVE_U_UART1] = { 0x10011000, 0x1000 }, + [SIFIVE_U_OTP] = { 0x10070000, 0x1000 }, [SIFIVE_U_DRAM] = { 0x80000000, 0x0 }, - [SIFIVE_U_GEM] = { 0x100900FC, 0x2000 }, + [SIFIVE_U_GEM] = { 0x10090000, 0x2000 }, + [SIFIVE_U_GEM_MGMT] = { 0x100a0000, 0x1000 }, }; +#define OTP_SERIAL 1 #define GEM_REVISION 0x10070109 static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap, uint64_t mem_size, const char *cmdline) { + MachineState *ms = MACHINE(qdev_get_machine()); void *fdt; int cpu; uint32_t *cells; char *nodename; - char ethclk_names[] = "pclk\0hclk\0tx_clk"; - uint32_t plic_phandle, ethclk_phandle, phandle = 1; + char ethclk_names[] = "pclk\0hclk"; + uint32_t plic_phandle, prci_phandle, phandle = 1; + uint32_t hfclk_phandle, rtcclk_phandle, phy_phandle; fdt = s->fdt = create_device_tree(&s->fdt_size); if (!fdt) { @@ -83,8 +96,9 @@ static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap, exit(1); } - qemu_fdt_setprop_string(fdt, "/", "model", "ucbbar,spike-bare,qemu"); - qemu_fdt_setprop_string(fdt, "/", "compatible", "ucbbar,spike-bare-dev"); + qemu_fdt_setprop_string(fdt, "/", "model", "SiFive HiFive Unleashed A00"); + qemu_fdt_setprop_string(fdt, "/", "compatible", + "sifive,hifive-unleashed-a00"); qemu_fdt_setprop_cell(fdt, "/", "#size-cells", 0x2); qemu_fdt_setprop_cell(fdt, "/", "#address-cells", 0x2); @@ -94,6 +108,28 @@ static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap, qemu_fdt_setprop_cell(fdt, "/soc", "#size-cells", 0x2); qemu_fdt_setprop_cell(fdt, "/soc", "#address-cells", 0x2); + hfclk_phandle = phandle++; + nodename = g_strdup_printf("/hfclk"); + qemu_fdt_add_subnode(fdt, nodename); + qemu_fdt_setprop_cell(fdt, nodename, "phandle", hfclk_phandle); + qemu_fdt_setprop_string(fdt, nodename, "clock-output-names", "hfclk"); + qemu_fdt_setprop_cell(fdt, nodename, "clock-frequency", + SIFIVE_U_HFCLK_FREQ); + qemu_fdt_setprop_string(fdt, nodename, "compatible", "fixed-clock"); + qemu_fdt_setprop_cell(fdt, nodename, "#clock-cells", 0x0); + g_free(nodename); + + rtcclk_phandle = phandle++; + nodename = g_strdup_printf("/rtcclk"); + qemu_fdt_add_subnode(fdt, nodename); + qemu_fdt_setprop_cell(fdt, nodename, "phandle", rtcclk_phandle); + qemu_fdt_setprop_string(fdt, nodename, "clock-output-names", "rtcclk"); + qemu_fdt_setprop_cell(fdt, nodename, "clock-frequency", + SIFIVE_U_RTCCLK_FREQ); + qemu_fdt_setprop_string(fdt, nodename, "compatible", "fixed-clock"); + qemu_fdt_setprop_cell(fdt, nodename, "#clock-cells", 0x0); + g_free(nodename); + nodename = g_strdup_printf("/memory@%lx", (long)memmap[SIFIVE_U_DRAM].base); qemu_fdt_add_subnode(fdt, nodename); @@ -109,15 +145,21 @@ static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap, qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0x0); qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 0x1); - for (cpu = s->soc.cpus.num_harts - 1; cpu >= 0; cpu--) { + for (cpu = ms->smp.cpus - 1; cpu >= 0; cpu--) { int cpu_phandle = phandle++; nodename = g_strdup_printf("/cpus/cpu@%d", cpu); char *intc = g_strdup_printf("/cpus/cpu@%d/interrupt-controller", cpu); - char *isa = riscv_isa_string(&s->soc.cpus.harts[cpu]); + char *isa; qemu_fdt_add_subnode(fdt, nodename); qemu_fdt_setprop_cell(fdt, nodename, "clock-frequency", SIFIVE_U_CLOCK_FREQ); - qemu_fdt_setprop_string(fdt, nodename, "mmu-type", "riscv,sv48"); + /* cpu 0 is the management hart that does not have mmu */ + if (cpu != 0) { + qemu_fdt_setprop_string(fdt, nodename, "mmu-type", "riscv,sv48"); + isa = riscv_isa_string(&s->soc.u_cpus.harts[cpu - 1]); + } else { + isa = riscv_isa_string(&s->soc.e_cpus.harts[0]); + } qemu_fdt_setprop_string(fdt, nodename, "riscv,isa", isa); qemu_fdt_setprop_string(fdt, nodename, "compatible", "riscv"); qemu_fdt_setprop_string(fdt, nodename, "status", "okay"); @@ -125,7 +167,6 @@ static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap, qemu_fdt_setprop_string(fdt, nodename, "device_type", "cpu"); qemu_fdt_add_subnode(fdt, intc); qemu_fdt_setprop_cell(fdt, intc, "phandle", cpu_phandle); - qemu_fdt_setprop_cell(fdt, intc, "linux,phandle", cpu_phandle); qemu_fdt_setprop_string(fdt, intc, "compatible", "riscv,cpu-intc"); qemu_fdt_setprop(fdt, intc, "interrupt-controller", NULL, 0); qemu_fdt_setprop_cell(fdt, intc, "#interrupt-cells", 1); @@ -134,8 +175,8 @@ static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap, g_free(nodename); } - cells = g_new0(uint32_t, s->soc.cpus.num_harts * 4); - for (cpu = 0; cpu < s->soc.cpus.num_harts; cpu++) { + cells = g_new0(uint32_t, ms->smp.cpus * 4); + for (cpu = 0; cpu < ms->smp.cpus; cpu++) { nodename = g_strdup_printf("/cpus/cpu@%d/interrupt-controller", cpu); uint32_t intc_phandle = qemu_fdt_get_phandle(fdt, nodename); @@ -153,20 +194,41 @@ static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap, 0x0, memmap[SIFIVE_U_CLINT].base, 0x0, memmap[SIFIVE_U_CLINT].size); qemu_fdt_setprop(fdt, nodename, "interrupts-extended", - cells, s->soc.cpus.num_harts * sizeof(uint32_t) * 4); + cells, ms->smp.cpus * sizeof(uint32_t) * 4); g_free(cells); g_free(nodename); + prci_phandle = phandle++; + nodename = g_strdup_printf("/soc/clock-controller@%lx", + (long)memmap[SIFIVE_U_PRCI].base); + qemu_fdt_add_subnode(fdt, nodename); + qemu_fdt_setprop_cell(fdt, nodename, "phandle", prci_phandle); + qemu_fdt_setprop_cell(fdt, nodename, "#clock-cells", 0x1); + qemu_fdt_setprop_cells(fdt, nodename, "clocks", + hfclk_phandle, rtcclk_phandle); + qemu_fdt_setprop_cells(fdt, nodename, "reg", + 0x0, memmap[SIFIVE_U_PRCI].base, + 0x0, memmap[SIFIVE_U_PRCI].size); + qemu_fdt_setprop_string(fdt, nodename, "compatible", + "sifive,fu540-c000-prci"); + g_free(nodename); + plic_phandle = phandle++; - cells = g_new0(uint32_t, s->soc.cpus.num_harts * 4); - for (cpu = 0; cpu < s->soc.cpus.num_harts; cpu++) { + cells = g_new0(uint32_t, ms->smp.cpus * 4 - 2); + for (cpu = 0; cpu < ms->smp.cpus; cpu++) { nodename = g_strdup_printf("/cpus/cpu@%d/interrupt-controller", cpu); uint32_t intc_phandle = qemu_fdt_get_phandle(fdt, nodename); - cells[cpu * 4 + 0] = cpu_to_be32(intc_phandle); - cells[cpu * 4 + 1] = cpu_to_be32(IRQ_M_EXT); - cells[cpu * 4 + 2] = cpu_to_be32(intc_phandle); - cells[cpu * 4 + 3] = cpu_to_be32(IRQ_S_EXT); + /* cpu 0 is the management hart that does not have S-mode */ + if (cpu == 0) { + cells[0] = cpu_to_be32(intc_phandle); + cells[1] = cpu_to_be32(IRQ_M_EXT); + } else { + cells[cpu * 4 - 2] = cpu_to_be32(intc_phandle); + cells[cpu * 4 - 1] = cpu_to_be32(IRQ_M_EXT); + cells[cpu * 4 + 0] = cpu_to_be32(intc_phandle); + cells[cpu * 4 + 1] = cpu_to_be32(IRQ_S_EXT); + } g_free(nodename); } nodename = g_strdup_printf("/soc/interrupt-controller@%lx", @@ -176,73 +238,70 @@ static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap, qemu_fdt_setprop_string(fdt, nodename, "compatible", "riscv,plic0"); qemu_fdt_setprop(fdt, nodename, "interrupt-controller", NULL, 0); qemu_fdt_setprop(fdt, nodename, "interrupts-extended", - cells, s->soc.cpus.num_harts * sizeof(uint32_t) * 4); + cells, (ms->smp.cpus * 4 - 2) * sizeof(uint32_t)); qemu_fdt_setprop_cells(fdt, nodename, "reg", 0x0, memmap[SIFIVE_U_PLIC].base, 0x0, memmap[SIFIVE_U_PLIC].size); - qemu_fdt_setprop_string(fdt, nodename, "reg-names", "control"); - qemu_fdt_setprop_cell(fdt, nodename, "riscv,max-priority", 7); qemu_fdt_setprop_cell(fdt, nodename, "riscv,ndev", 0x35); - qemu_fdt_setprop_cells(fdt, nodename, "phandle", plic_phandle); - qemu_fdt_setprop_cells(fdt, nodename, "linux,phandle", plic_phandle); + qemu_fdt_setprop_cell(fdt, nodename, "phandle", plic_phandle); plic_phandle = qemu_fdt_get_phandle(fdt, nodename); g_free(cells); g_free(nodename); - ethclk_phandle = phandle++; - nodename = g_strdup_printf("/soc/ethclk"); - qemu_fdt_add_subnode(fdt, nodename); - qemu_fdt_setprop_string(fdt, nodename, "compatible", "fixed-clock"); - qemu_fdt_setprop_cell(fdt, nodename, "#clock-cells", 0x0); - qemu_fdt_setprop_cell(fdt, nodename, "clock-frequency", - SIFIVE_U_GEM_CLOCK_FREQ); - qemu_fdt_setprop_cell(fdt, nodename, "phandle", ethclk_phandle); - qemu_fdt_setprop_cell(fdt, nodename, "linux,phandle", ethclk_phandle); - ethclk_phandle = qemu_fdt_get_phandle(fdt, nodename); - g_free(nodename); - + phy_phandle = phandle++; nodename = g_strdup_printf("/soc/ethernet@%lx", (long)memmap[SIFIVE_U_GEM].base); qemu_fdt_add_subnode(fdt, nodename); - qemu_fdt_setprop_string(fdt, nodename, "compatible", "cdns,macb"); + qemu_fdt_setprop_string(fdt, nodename, "compatible", + "sifive,fu540-c000-gem"); qemu_fdt_setprop_cells(fdt, nodename, "reg", 0x0, memmap[SIFIVE_U_GEM].base, - 0x0, memmap[SIFIVE_U_GEM].size); + 0x0, memmap[SIFIVE_U_GEM].size, + 0x0, memmap[SIFIVE_U_GEM_MGMT].base, + 0x0, memmap[SIFIVE_U_GEM_MGMT].size); qemu_fdt_setprop_string(fdt, nodename, "reg-names", "control"); qemu_fdt_setprop_string(fdt, nodename, "phy-mode", "gmii"); - qemu_fdt_setprop_cells(fdt, nodename, "interrupt-parent", plic_phandle); - qemu_fdt_setprop_cells(fdt, nodename, "interrupts", SIFIVE_U_GEM_IRQ); + qemu_fdt_setprop_cell(fdt, nodename, "phy-handle", phy_phandle); + qemu_fdt_setprop_cell(fdt, nodename, "interrupt-parent", plic_phandle); + qemu_fdt_setprop_cell(fdt, nodename, "interrupts", SIFIVE_U_GEM_IRQ); qemu_fdt_setprop_cells(fdt, nodename, "clocks", - ethclk_phandle, ethclk_phandle, ethclk_phandle); - qemu_fdt_setprop(fdt, nodename, "clocks-names", ethclk_names, + prci_phandle, PRCI_CLK_GEMGXLPLL, prci_phandle, PRCI_CLK_GEMGXLPLL); + qemu_fdt_setprop(fdt, nodename, "clock-names", ethclk_names, sizeof(ethclk_names)); - qemu_fdt_setprop_cells(fdt, nodename, "#address-cells", 1); - qemu_fdt_setprop_cells(fdt, nodename, "#size-cells", 0); + qemu_fdt_setprop(fdt, nodename, "local-mac-address", + s->soc.gem.conf.macaddr.a, ETH_ALEN); + qemu_fdt_setprop_cell(fdt, nodename, "#address-cells", 1); + qemu_fdt_setprop_cell(fdt, nodename, "#size-cells", 0); g_free(nodename); nodename = g_strdup_printf("/soc/ethernet@%lx/ethernet-phy@0", (long)memmap[SIFIVE_U_GEM].base); qemu_fdt_add_subnode(fdt, nodename); - qemu_fdt_setprop_cells(fdt, nodename, "reg", 0x0); + qemu_fdt_setprop_cell(fdt, nodename, "phandle", phy_phandle); + qemu_fdt_setprop_cell(fdt, nodename, "reg", 0x0); g_free(nodename); - nodename = g_strdup_printf("/soc/uart@%lx", + nodename = g_strdup_printf("/soc/serial@%lx", (long)memmap[SIFIVE_U_UART0].base); qemu_fdt_add_subnode(fdt, nodename); qemu_fdt_setprop_string(fdt, nodename, "compatible", "sifive,uart0"); qemu_fdt_setprop_cells(fdt, nodename, "reg", 0x0, memmap[SIFIVE_U_UART0].base, 0x0, memmap[SIFIVE_U_UART0].size); - qemu_fdt_setprop_cell(fdt, nodename, "clock-frequency", - SIFIVE_U_CLOCK_FREQ / 2); - qemu_fdt_setprop_cells(fdt, nodename, "interrupt-parent", plic_phandle); - qemu_fdt_setprop_cells(fdt, nodename, "interrupts", SIFIVE_U_UART0_IRQ); + qemu_fdt_setprop_cells(fdt, nodename, "clocks", + prci_phandle, PRCI_CLK_TLCLK); + qemu_fdt_setprop_cell(fdt, nodename, "interrupt-parent", plic_phandle); + qemu_fdt_setprop_cell(fdt, nodename, "interrupts", SIFIVE_U_UART0_IRQ); qemu_fdt_add_subnode(fdt, "/chosen"); qemu_fdt_setprop_string(fdt, "/chosen", "stdout-path", nodename); if (cmdline) { qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", cmdline); } + + qemu_fdt_add_subnode(fdt, "/aliases"); + qemu_fdt_setprop_string(fdt, "/aliases", "serial0", nodename); + g_free(nodename); } @@ -275,7 +334,18 @@ static void riscv_sifive_u_init(MachineState *machine) memmap[SIFIVE_U_DRAM].base); if (machine->kernel_filename) { - riscv_load_kernel(machine->kernel_filename); + uint64_t kernel_entry = riscv_load_kernel(machine->kernel_filename); + + if (machine->initrd_filename) { + hwaddr start; + hwaddr end = riscv_load_initrd(machine->initrd_filename, + machine->ram_size, kernel_entry, + &start); + qemu_fdt_setprop_cell(s->fdt, "/chosen", + "linux,initrd-start", start); + qemu_fdt_setprop_cell(s->fdt, "/chosen", "linux,initrd-end", + end); + } } /* reset vector */ @@ -319,13 +389,37 @@ static void riscv_sifive_u_soc_init(Object *obj) MachineState *ms = MACHINE(qdev_get_machine()); SiFiveUSoCState *s = RISCV_U_SOC(obj); - object_initialize_child(obj, "cpus", &s->cpus, sizeof(s->cpus), - TYPE_RISCV_HART_ARRAY, &error_abort, NULL); - object_property_set_str(OBJECT(&s->cpus), SIFIVE_U_CPU, "cpu-type", - &error_abort); - object_property_set_int(OBJECT(&s->cpus), ms->smp.cpus, "num-harts", - &error_abort); - + object_initialize_child(obj, "e-cluster", &s->e_cluster, + sizeof(s->e_cluster), TYPE_CPU_CLUSTER, + &error_abort, NULL); + qdev_prop_set_uint32(DEVICE(&s->e_cluster), "cluster-id", 0); + + object_initialize_child(OBJECT(&s->e_cluster), "e-cpus", + &s->e_cpus, sizeof(s->e_cpus), + TYPE_RISCV_HART_ARRAY, &error_abort, + NULL); + qdev_prop_set_uint32(DEVICE(&s->e_cpus), "num-harts", 1); + qdev_prop_set_uint32(DEVICE(&s->e_cpus), "hartid-base", 0); + qdev_prop_set_string(DEVICE(&s->e_cpus), "cpu-type", SIFIVE_E_CPU); + + object_initialize_child(obj, "u-cluster", &s->u_cluster, + sizeof(s->u_cluster), TYPE_CPU_CLUSTER, + &error_abort, NULL); + qdev_prop_set_uint32(DEVICE(&s->u_cluster), "cluster-id", 1); + + object_initialize_child(OBJECT(&s->u_cluster), "u-cpus", + &s->u_cpus, sizeof(s->u_cpus), + TYPE_RISCV_HART_ARRAY, &error_abort, + NULL); + qdev_prop_set_uint32(DEVICE(&s->u_cpus), "num-harts", ms->smp.cpus - 1); + qdev_prop_set_uint32(DEVICE(&s->u_cpus), "hartid-base", 1); + qdev_prop_set_string(DEVICE(&s->u_cpus), "cpu-type", SIFIVE_U_CPU); + + sysbus_init_child_obj(obj, "prci", &s->prci, sizeof(s->prci), + TYPE_SIFIVE_U_PRCI); + sysbus_init_child_obj(obj, "otp", &s->otp, sizeof(s->otp), + TYPE_SIFIVE_U_OTP); + qdev_prop_set_uint32(DEVICE(&s->otp), "serial", OTP_SERIAL); sysbus_init_child_obj(obj, "gem", &s->gem, sizeof(s->gem), TYPE_CADENCE_GEM); } @@ -344,7 +438,19 @@ static void riscv_sifive_u_soc_realize(DeviceState *dev, Error **errp) Error *err = NULL; NICInfo *nd = &nd_table[0]; - object_property_set_bool(OBJECT(&s->cpus), true, "realized", + object_property_set_bool(OBJECT(&s->e_cpus), true, "realized", + &error_abort); + object_property_set_bool(OBJECT(&s->u_cpus), true, "realized", + &error_abort); + /* + * The cluster must be realized after the RISC-V hart array container, + * as the container's CPU object is only created on realize, and the + * CPU must exist and have been parented into the cluster before the + * cluster is realized. + */ + object_property_set_bool(OBJECT(&s->e_cluster), true, "realized", + &error_abort); + object_property_set_bool(OBJECT(&s->u_cluster), true, "realized", &error_abort); /* boot rom */ @@ -359,10 +465,11 @@ static void riscv_sifive_u_soc_realize(DeviceState *dev, Error **errp) plic_hart_config = g_malloc0(plic_hart_config_len); for (i = 0; i < ms->smp.cpus; i++) { if (i != 0) { - strncat(plic_hart_config, ",", plic_hart_config_len); + strncat(plic_hart_config, "," SIFIVE_U_PLIC_HART_CONFIG, + plic_hart_config_len); + } else { + strncat(plic_hart_config, "M", plic_hart_config_len); } - strncat(plic_hart_config, SIFIVE_U_PLIC_HART_CONFIG, - plic_hart_config_len); plic_hart_config_len -= (strlen(SIFIVE_U_PLIC_HART_CONFIG) + 1); } @@ -386,6 +493,12 @@ static void riscv_sifive_u_soc_realize(DeviceState *dev, Error **errp) memmap[SIFIVE_U_CLINT].size, ms->smp.cpus, SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE); + object_property_set_bool(OBJECT(&s->prci), true, "realized", &err); + sysbus_mmio_map(SYS_BUS_DEVICE(&s->prci), 0, memmap[SIFIVE_U_PRCI].base); + + object_property_set_bool(OBJECT(&s->otp), true, "realized", &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); } @@ -404,16 +517,18 @@ static void riscv_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]); + + create_unimplemented_device("riscv.sifive.u.gem-mgmt", + memmap[SIFIVE_U_GEM_MGMT].base, memmap[SIFIVE_U_GEM_MGMT].size); } static void riscv_sifive_u_machine_init(MachineClass *mc) { mc->desc = "RISC-V Board compatible with SiFive U SDK"; mc->init = riscv_sifive_u_init; - /* The real hardware has 5 CPUs, but one of them is a small embedded power - * management CPU. - */ - mc->max_cpus = 4; + mc->max_cpus = SIFIVE_U_MANAGEMENT_CPU_COUNT + SIFIVE_U_COMPUTE_CPU_COUNT; + mc->min_cpus = SIFIVE_U_MANAGEMENT_CPU_COUNT + 1; + mc->default_cpus = mc->min_cpus; } DEFINE_MACHINE("sifive_u", riscv_sifive_u_machine_init) diff --git a/hw/riscv/sifive_u_otp.c b/hw/riscv/sifive_u_otp.c new file mode 100644 index 0000000000..ea0eee5678 --- /dev/null +++ b/hw/riscv/sifive_u_otp.c @@ -0,0 +1,191 @@ +/* + * QEMU SiFive U OTP (One-Time Programmable) Memory interface + * + * Copyright (c) 2019 Bin Meng <bmeng.cn@gmail.com> + * + * Simple model of the OTP to emulate register reads made by the SDK BSP + * + * 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/qdev-properties.h" +#include "hw/sysbus.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "hw/riscv/sifive_u_otp.h" + +static uint64_t sifive_u_otp_read(void *opaque, hwaddr addr, unsigned int size) +{ + SiFiveUOTPState *s = opaque; + + switch (addr) { + case SIFIVE_U_OTP_PA: + return s->pa; + case SIFIVE_U_OTP_PAIO: + return s->paio; + case SIFIVE_U_OTP_PAS: + return s->pas; + case SIFIVE_U_OTP_PCE: + return s->pce; + case SIFIVE_U_OTP_PCLK: + return s->pclk; + case SIFIVE_U_OTP_PDIN: + return s->pdin; + case SIFIVE_U_OTP_PDOUT: + if ((s->pce & SIFIVE_U_OTP_PCE_EN) && + (s->pdstb & SIFIVE_U_OTP_PDSTB_EN) && + (s->ptrim & SIFIVE_U_OTP_PTRIM_EN)) { + return s->fuse[s->pa & SIFIVE_U_OTP_PA_MASK]; + } else { + return 0xff; + } + case SIFIVE_U_OTP_PDSTB: + return s->pdstb; + case SIFIVE_U_OTP_PPROG: + return s->pprog; + case SIFIVE_U_OTP_PTC: + return s->ptc; + case SIFIVE_U_OTP_PTM: + return s->ptm; + case SIFIVE_U_OTP_PTM_REP: + return s->ptm_rep; + case SIFIVE_U_OTP_PTR: + return s->ptr; + case SIFIVE_U_OTP_PTRIM: + return s->ptrim; + case SIFIVE_U_OTP_PWE: + return s->pwe; + } + + qemu_log_mask(LOG_GUEST_ERROR, "%s: read: addr=0x%" HWADDR_PRIx "\n", + __func__, addr); + return 0; +} + +static void sifive_u_otp_write(void *opaque, hwaddr addr, + uint64_t val64, unsigned int size) +{ + SiFiveUOTPState *s = opaque; + uint32_t val32 = (uint32_t)val64; + + switch (addr) { + case SIFIVE_U_OTP_PA: + s->pa = val32 & SIFIVE_U_OTP_PA_MASK; + break; + case SIFIVE_U_OTP_PAIO: + s->paio = val32; + break; + case SIFIVE_U_OTP_PAS: + s->pas = val32; + break; + case SIFIVE_U_OTP_PCE: + s->pce = val32; + break; + case SIFIVE_U_OTP_PCLK: + s->pclk = val32; + break; + case SIFIVE_U_OTP_PDIN: + s->pdin = val32; + break; + case SIFIVE_U_OTP_PDOUT: + /* read-only */ + break; + case SIFIVE_U_OTP_PDSTB: + s->pdstb = val32; + break; + case SIFIVE_U_OTP_PPROG: + s->pprog = val32; + break; + case SIFIVE_U_OTP_PTC: + s->ptc = val32; + break; + case SIFIVE_U_OTP_PTM: + s->ptm = val32; + break; + case SIFIVE_U_OTP_PTM_REP: + s->ptm_rep = val32; + break; + case SIFIVE_U_OTP_PTR: + s->ptr = val32; + break; + case SIFIVE_U_OTP_PTRIM: + s->ptrim = val32; + break; + case SIFIVE_U_OTP_PWE: + s->pwe = val32; + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, "%s: bad write: addr=0x%" HWADDR_PRIx + " v=0x%x\n", __func__, addr, val32); + } +} + +static const MemoryRegionOps sifive_u_otp_ops = { + .read = sifive_u_otp_read, + .write = sifive_u_otp_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4 + } +}; + +static Property sifive_u_otp_properties[] = { + DEFINE_PROP_UINT32("serial", SiFiveUOTPState, serial, 0), + DEFINE_PROP_END_OF_LIST(), +}; + +static void sifive_u_otp_realize(DeviceState *dev, Error **errp) +{ + SiFiveUOTPState *s = SIFIVE_U_OTP(dev); + + memory_region_init_io(&s->mmio, OBJECT(dev), &sifive_u_otp_ops, s, + TYPE_SIFIVE_U_OTP, SIFIVE_U_OTP_REG_SIZE); + sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio); +} + +static void sifive_u_otp_reset(DeviceState *dev) +{ + SiFiveUOTPState *s = SIFIVE_U_OTP(dev); + + /* Initialize all fuses' initial value to 0xFFs */ + memset(s->fuse, 0xff, sizeof(s->fuse)); + + /* Make a valid content of serial number */ + s->fuse[SIFIVE_U_OTP_SERIAL_ADDR] = s->serial; + s->fuse[SIFIVE_U_OTP_SERIAL_ADDR + 1] = ~(s->serial); +} + +static void sifive_u_otp_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->props = sifive_u_otp_properties; + dc->realize = sifive_u_otp_realize; + dc->reset = sifive_u_otp_reset; +} + +static const TypeInfo sifive_u_otp_info = { + .name = TYPE_SIFIVE_U_OTP, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(SiFiveUOTPState), + .class_init = sifive_u_otp_class_init, +}; + +static void sifive_u_otp_register_types(void) +{ + type_register_static(&sifive_u_otp_info); +} + +type_init(sifive_u_otp_register_types) diff --git a/hw/riscv/sifive_u_prci.c b/hw/riscv/sifive_u_prci.c new file mode 100644 index 0000000000..4fa590c064 --- /dev/null +++ b/hw/riscv/sifive_u_prci.c @@ -0,0 +1,169 @@ +/* + * QEMU SiFive U PRCI (Power, Reset, Clock, Interrupt) + * + * Copyright (c) 2019 Bin Meng <bmeng.cn@gmail.com> + * + * Simple model of the PRCI to emulate register reads made by the SDK BSP + * + * 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/sysbus.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "hw/riscv/sifive_u_prci.h" + +static uint64_t sifive_u_prci_read(void *opaque, hwaddr addr, unsigned int size) +{ + SiFiveUPRCIState *s = opaque; + + switch (addr) { + case SIFIVE_U_PRCI_HFXOSCCFG: + return s->hfxosccfg; + case SIFIVE_U_PRCI_COREPLLCFG0: + return s->corepllcfg0; + case SIFIVE_U_PRCI_DDRPLLCFG0: + return s->ddrpllcfg0; + case SIFIVE_U_PRCI_DDRPLLCFG1: + return s->ddrpllcfg1; + case SIFIVE_U_PRCI_GEMGXLPLLCFG0: + return s->gemgxlpllcfg0; + case SIFIVE_U_PRCI_GEMGXLPLLCFG1: + return s->gemgxlpllcfg1; + case SIFIVE_U_PRCI_CORECLKSEL: + return s->coreclksel; + case SIFIVE_U_PRCI_DEVICESRESET: + return s->devicesreset; + case SIFIVE_U_PRCI_CLKMUXSTATUS: + return s->clkmuxstatus; + } + + qemu_log_mask(LOG_GUEST_ERROR, "%s: read: addr=0x%" HWADDR_PRIx "\n", + __func__, addr); + + return 0; +} + +static void sifive_u_prci_write(void *opaque, hwaddr addr, + uint64_t val64, unsigned int size) +{ + SiFiveUPRCIState *s = opaque; + uint32_t val32 = (uint32_t)val64; + + switch (addr) { + case SIFIVE_U_PRCI_HFXOSCCFG: + s->hfxosccfg = val32; + /* OSC stays ready */ + s->hfxosccfg |= SIFIVE_U_PRCI_HFXOSCCFG_RDY; + break; + case SIFIVE_U_PRCI_COREPLLCFG0: + s->corepllcfg0 = val32; + /* internal feedback */ + s->corepllcfg0 |= SIFIVE_U_PRCI_PLLCFG0_FSE; + /* PLL stays locked */ + s->corepllcfg0 |= SIFIVE_U_PRCI_PLLCFG0_LOCK; + break; + case SIFIVE_U_PRCI_DDRPLLCFG0: + s->ddrpllcfg0 = val32; + /* internal feedback */ + s->ddrpllcfg0 |= SIFIVE_U_PRCI_PLLCFG0_FSE; + /* PLL stays locked */ + s->ddrpllcfg0 |= SIFIVE_U_PRCI_PLLCFG0_LOCK; + break; + case SIFIVE_U_PRCI_DDRPLLCFG1: + s->ddrpllcfg1 = val32; + break; + case SIFIVE_U_PRCI_GEMGXLPLLCFG0: + s->gemgxlpllcfg0 = val32; + /* internal feedback */ + s->gemgxlpllcfg0 |= SIFIVE_U_PRCI_PLLCFG0_FSE; + /* PLL stays locked */ + s->gemgxlpllcfg0 |= SIFIVE_U_PRCI_PLLCFG0_LOCK; + break; + case SIFIVE_U_PRCI_GEMGXLPLLCFG1: + s->gemgxlpllcfg1 = val32; + break; + case SIFIVE_U_PRCI_CORECLKSEL: + s->coreclksel = val32; + break; + case SIFIVE_U_PRCI_DEVICESRESET: + s->devicesreset = val32; + break; + case SIFIVE_U_PRCI_CLKMUXSTATUS: + s->clkmuxstatus = val32; + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, "%s: bad write: addr=0x%" HWADDR_PRIx + " v=0x%x\n", __func__, addr, val32); + } +} + +static const MemoryRegionOps sifive_u_prci_ops = { + .read = sifive_u_prci_read, + .write = sifive_u_prci_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4 + } +}; + +static void sifive_u_prci_realize(DeviceState *dev, Error **errp) +{ + SiFiveUPRCIState *s = SIFIVE_U_PRCI(dev); + + memory_region_init_io(&s->mmio, OBJECT(dev), &sifive_u_prci_ops, s, + TYPE_SIFIVE_U_PRCI, SIFIVE_U_PRCI_REG_SIZE); + sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio); +} + +static void sifive_u_prci_reset(DeviceState *dev) +{ + SiFiveUPRCIState *s = SIFIVE_U_PRCI(dev); + + /* Initialize register to power-on-reset values */ + s->hfxosccfg = SIFIVE_U_PRCI_HFXOSCCFG_RDY | SIFIVE_U_PRCI_HFXOSCCFG_EN; + s->corepllcfg0 = SIFIVE_U_PRCI_PLLCFG0_DIVR | SIFIVE_U_PRCI_PLLCFG0_DIVF | + SIFIVE_U_PRCI_PLLCFG0_DIVQ | SIFIVE_U_PRCI_PLLCFG0_FSE | + SIFIVE_U_PRCI_PLLCFG0_LOCK; + s->ddrpllcfg0 = SIFIVE_U_PRCI_PLLCFG0_DIVR | SIFIVE_U_PRCI_PLLCFG0_DIVF | + SIFIVE_U_PRCI_PLLCFG0_DIVQ | SIFIVE_U_PRCI_PLLCFG0_FSE | + SIFIVE_U_PRCI_PLLCFG0_LOCK; + s->gemgxlpllcfg0 = SIFIVE_U_PRCI_PLLCFG0_DIVR | SIFIVE_U_PRCI_PLLCFG0_DIVF | + SIFIVE_U_PRCI_PLLCFG0_DIVQ | SIFIVE_U_PRCI_PLLCFG0_FSE | + SIFIVE_U_PRCI_PLLCFG0_LOCK; + s->coreclksel = SIFIVE_U_PRCI_CORECLKSEL_HFCLK; +} + +static void sifive_u_prci_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = sifive_u_prci_realize; + dc->reset = sifive_u_prci_reset; +} + +static const TypeInfo sifive_u_prci_info = { + .name = TYPE_SIFIVE_U_PRCI, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(SiFiveUPRCIState), + .class_init = sifive_u_prci_class_init, +}; + +static void sifive_u_prci_register_types(void) +{ + type_register_static(&sifive_u_prci_info); +} + +type_init(sifive_u_prci_register_types) diff --git a/hw/riscv/sifive_uart.c b/hw/riscv/sifive_uart.c index 9de42b1680..a403ae90f5 100644 --- a/hw/riscv/sifive_uart.c +++ b/hw/riscv/sifive_uart.c @@ -18,10 +18,10 @@ #include "qemu/osdep.h" #include "qapi/error.h" +#include "qemu/log.h" #include "hw/sysbus.h" #include "chardev/char.h" #include "chardev/char-fe.h" -#include "target/riscv/cpu.h" #include "hw/hw.h" #include "hw/irq.h" #include "hw/riscv/sifive_uart.h" @@ -95,8 +95,8 @@ uart_read(void *opaque, hwaddr addr, unsigned int size) return s->div; } - hw_error("%s: bad read: addr=0x%x\n", - __func__, (int)addr); + qemu_log_mask(LOG_GUEST_ERROR, "%s: bad read: addr=0x%x\n", + __func__, (int)addr); return 0; } @@ -127,8 +127,8 @@ uart_write(void *opaque, hwaddr addr, s->div = val64; return; } - hw_error("%s: bad write: addr=0x%x v=0x%x\n", - __func__, (int)addr, (int)value); + qemu_log_mask(LOG_GUEST_ERROR, "%s: bad write: addr=0x%x v=0x%x\n", + __func__, (int)addr, (int)value); } static const MemoryRegionOps uart_ops = { diff --git a/hw/riscv/spike.c b/hw/riscv/spike.c index 7c04bd554f..d60415d190 100644 --- a/hw/riscv/spike.c +++ b/hw/riscv/spike.c @@ -112,7 +112,6 @@ static void create_fdt(SpikeState *s, const struct MemmapEntry *memmap, qemu_fdt_setprop_string(fdt, nodename, "device_type", "cpu"); qemu_fdt_add_subnode(fdt, intc); qemu_fdt_setprop_cell(fdt, intc, "phandle", 1); - qemu_fdt_setprop_cell(fdt, intc, "linux,phandle", 1); qemu_fdt_setprop_string(fdt, intc, "compatible", "riscv,cpu-intc"); qemu_fdt_setprop(fdt, intc, "interrupt-controller", NULL, 0); qemu_fdt_setprop_cell(fdt, intc, "#interrupt-cells", 1); diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index 9bced28486..d36f5625ec 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -112,7 +112,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 struct MemmapEntry *memmap, uint64_t mem_size, const char *cmdline) { void *fdt; @@ -170,11 +170,9 @@ static void *create_fdt(RISCVVirtState *s, const struct MemmapEntry *memmap, qemu_fdt_setprop_cell(fdt, nodename, "reg", cpu); qemu_fdt_setprop_string(fdt, nodename, "device_type", "cpu"); qemu_fdt_setprop_cell(fdt, nodename, "phandle", cpu_phandle); - qemu_fdt_setprop_cell(fdt, nodename, "linux,phandle", cpu_phandle); intc_phandle = phandle++; qemu_fdt_add_subnode(fdt, intc); qemu_fdt_setprop_cell(fdt, intc, "phandle", intc_phandle); - qemu_fdt_setprop_cell(fdt, intc, "linux,phandle", intc_phandle); qemu_fdt_setprop_string(fdt, intc, "compatible", "riscv,cpu-intc"); qemu_fdt_setprop(fdt, intc, "interrupt-controller", NULL, 0); qemu_fdt_setprop_cell(fdt, intc, "#interrupt-cells", 1); @@ -235,8 +233,8 @@ static void *create_fdt(RISCVVirtState *s, const struct MemmapEntry *memmap, nodename = g_strdup_printf("/soc/interrupt-controller@%lx", (long)memmap[VIRT_PLIC].base); qemu_fdt_add_subnode(fdt, nodename); - qemu_fdt_setprop_cells(fdt, nodename, "#address-cells", - FDT_PLIC_ADDR_CELLS); + qemu_fdt_setprop_cell(fdt, nodename, "#address-cells", + FDT_PLIC_ADDR_CELLS); qemu_fdt_setprop_cell(fdt, nodename, "#interrupt-cells", FDT_PLIC_INT_CELLS); qemu_fdt_setprop_string(fdt, nodename, "compatible", "riscv,plic0"); @@ -246,11 +244,8 @@ static void *create_fdt(RISCVVirtState *s, const struct MemmapEntry *memmap, qemu_fdt_setprop_cells(fdt, nodename, "reg", 0x0, memmap[VIRT_PLIC].base, 0x0, memmap[VIRT_PLIC].size); - qemu_fdt_setprop_string(fdt, nodename, "reg-names", "control"); - qemu_fdt_setprop_cell(fdt, nodename, "riscv,max-priority", 7); qemu_fdt_setprop_cell(fdt, nodename, "riscv,ndev", VIRTIO_NDEV); - qemu_fdt_setprop_cells(fdt, nodename, "phandle", plic_phandle); - qemu_fdt_setprop_cells(fdt, nodename, "linux,phandle", plic_phandle); + qemu_fdt_setprop_cell(fdt, nodename, "phandle", plic_phandle); plic_phandle = qemu_fdt_get_phandle(fdt, nodename); g_free(cells); g_free(nodename); @@ -263,19 +258,19 @@ static void *create_fdt(RISCVVirtState *s, const struct MemmapEntry *memmap, qemu_fdt_setprop_cells(fdt, nodename, "reg", 0x0, memmap[VIRT_VIRTIO].base + i * memmap[VIRT_VIRTIO].size, 0x0, memmap[VIRT_VIRTIO].size); - qemu_fdt_setprop_cells(fdt, nodename, "interrupt-parent", plic_phandle); - qemu_fdt_setprop_cells(fdt, nodename, "interrupts", VIRTIO_IRQ + i); + qemu_fdt_setprop_cell(fdt, nodename, "interrupt-parent", plic_phandle); + qemu_fdt_setprop_cell(fdt, nodename, "interrupts", VIRTIO_IRQ + i); g_free(nodename); } nodename = g_strdup_printf("/soc/pci@%lx", (long) memmap[VIRT_PCIE_ECAM].base); qemu_fdt_add_subnode(fdt, nodename); - qemu_fdt_setprop_cells(fdt, nodename, "#address-cells", - FDT_PCI_ADDR_CELLS); - qemu_fdt_setprop_cells(fdt, nodename, "#interrupt-cells", - FDT_PCI_INT_CELLS); - qemu_fdt_setprop_cells(fdt, nodename, "#size-cells", 0x2); + qemu_fdt_setprop_cell(fdt, nodename, "#address-cells", + FDT_PCI_ADDR_CELLS); + qemu_fdt_setprop_cell(fdt, nodename, "#interrupt-cells", + FDT_PCI_INT_CELLS); + qemu_fdt_setprop_cell(fdt, nodename, "#size-cells", 0x2); qemu_fdt_setprop_string(fdt, nodename, "compatible", "pci-host-ecam-generic"); qemu_fdt_setprop_string(fdt, nodename, "device_type", "pci"); @@ -312,8 +307,8 @@ static void *create_fdt(RISCVVirtState *s, const struct MemmapEntry *memmap, 0x0, memmap[VIRT_UART0].base, 0x0, memmap[VIRT_UART0].size); qemu_fdt_setprop_cell(fdt, nodename, "clock-frequency", 3686400); - qemu_fdt_setprop_cells(fdt, nodename, "interrupt-parent", plic_phandle); - qemu_fdt_setprop_cells(fdt, nodename, "interrupts", UART0_IRQ); + qemu_fdt_setprop_cell(fdt, nodename, "interrupt-parent", plic_phandle); + qemu_fdt_setprop_cell(fdt, nodename, "interrupts", UART0_IRQ); qemu_fdt_add_subnode(fdt, "/chosen"); qemu_fdt_setprop_string(fdt, "/chosen", "stdout-path", nodename); @@ -321,8 +316,6 @@ static void *create_fdt(RISCVVirtState *s, const struct MemmapEntry *memmap, qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", cmdline); } g_free(nodename); - - return fdt; } @@ -378,7 +371,6 @@ static void riscv_virt_board_init(MachineState *machine) size_t plic_hart_config_len; int i; unsigned int smp_cpus = machine->smp.cpus; - void *fdt; /* Initialize SOC */ object_initialize_child(OBJECT(machine), "soc", &s->soc, sizeof(s->soc), @@ -397,7 +389,7 @@ static void riscv_virt_board_init(MachineState *machine) main_mem); /* create device tree */ - fdt = create_fdt(s, memmap, machine->ram_size, machine->kernel_cmdline); + create_fdt(s, memmap, machine->ram_size, machine->kernel_cmdline); /* boot rom */ memory_region_init_rom(mask_rom, NULL, "riscv_virt_board.mrom", @@ -416,9 +408,9 @@ static void riscv_virt_board_init(MachineState *machine) hwaddr end = riscv_load_initrd(machine->initrd_filename, machine->ram_size, kernel_entry, &start); - qemu_fdt_setprop_cell(fdt, "/chosen", + qemu_fdt_setprop_cell(s->fdt, "/chosen", "linux,initrd-start", start); - qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-end", + qemu_fdt_setprop_cell(s->fdt, "/chosen", "linux,initrd-end", end); } } |