2018-03-02 15:31:14 +03:00
|
|
|
/*
|
|
|
|
* QEMU RISC-V Board Compatible with SiFive Freedom U SDK
|
|
|
|
*
|
|
|
|
* Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
|
|
|
|
* Copyright (c) 2017 SiFive, Inc.
|
2019-09-06 19:20:17 +03:00
|
|
|
* Copyright (c) 2019 Bin Meng <bmeng.cn@gmail.com>
|
2018-03-02 15:31:14 +03:00
|
|
|
*
|
|
|
|
* Provides a board compatible with the SiFive Freedom U SDK:
|
|
|
|
*
|
|
|
|
* 0) UART
|
|
|
|
* 1) CLINT (Core Level Interruptor)
|
|
|
|
* 2) PLIC (Platform Level Interrupt Controller)
|
2019-09-06 19:20:10 +03:00
|
|
|
* 3) PRCI (Power, Reset, Clock, Interrupt)
|
2020-06-08 17:17:36 +03:00
|
|
|
* 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
|
2018-03-02 15:31:14 +03:00
|
|
|
*
|
2019-09-06 19:20:05 +03:00
|
|
|
* This board currently generates devicetree dynamically that indicates at least
|
2019-09-06 19:20:06 +03:00
|
|
|
* two harts and up to five harts.
|
2018-03-02 15:31:14 +03:00
|
|
|
*
|
|
|
|
* 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 "qemu/log.h"
|
|
|
|
#include "qemu/error-report.h"
|
|
|
|
#include "qapi/error.h"
|
2019-11-16 18:08:50 +03:00
|
|
|
#include "qapi/visitor.h"
|
2018-03-02 15:31:14 +03:00
|
|
|
#include "hw/boards.h"
|
2020-06-08 17:17:38 +03:00
|
|
|
#include "hw/irq.h"
|
2018-03-02 15:31:14 +03:00
|
|
|
#include "hw/loader.h"
|
|
|
|
#include "hw/sysbus.h"
|
|
|
|
#include "hw/char/serial.h"
|
2019-09-06 19:20:06 +03:00
|
|
|
#include "hw/cpu/cluster.h"
|
2019-09-06 19:20:17 +03:00
|
|
|
#include "hw/misc/unimp.h"
|
2018-03-02 15:31:14 +03:00
|
|
|
#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_u.h"
|
2019-06-25 01:11:49 +03:00
|
|
|
#include "hw/riscv/boot.h"
|
2018-03-02 15:31:14 +03:00
|
|
|
#include "chardev/char.h"
|
2019-09-06 19:20:17 +03:00
|
|
|
#include "net/eth.h"
|
2018-03-02 15:31:14 +03:00
|
|
|
#include "sysemu/arch_init.h"
|
|
|
|
#include "sysemu/device_tree.h"
|
2020-06-08 17:17:38 +03:00
|
|
|
#include "sysemu/runstate.h"
|
2019-08-12 08:23:57 +03:00
|
|
|
#include "sysemu/sysemu.h"
|
2018-03-02 15:31:14 +03:00
|
|
|
#include "exec/address-spaces.h"
|
|
|
|
|
2018-03-04 01:52:13 +03:00
|
|
|
#include <libfdt.h>
|
|
|
|
|
2020-02-24 16:39:43 +03:00
|
|
|
#if defined(TARGET_RISCV32)
|
|
|
|
# define BIOS_FILENAME "opensbi-riscv32-sifive_u-fw_jump.bin"
|
|
|
|
#else
|
|
|
|
# define BIOS_FILENAME "opensbi-riscv64-sifive_u-fw_jump.bin"
|
|
|
|
#endif
|
2019-07-16 21:47:25 +03:00
|
|
|
|
2018-03-02 15:31:14 +03:00
|
|
|
static const struct MemmapEntry {
|
|
|
|
hwaddr base;
|
|
|
|
hwaddr size;
|
|
|
|
} sifive_u_memmap[] = {
|
|
|
|
[SIFIVE_U_DEBUG] = { 0x0, 0x100 },
|
2018-03-04 01:52:13 +03:00
|
|
|
[SIFIVE_U_MROM] = { 0x1000, 0x11000 },
|
2018-03-02 15:31:14 +03:00
|
|
|
[SIFIVE_U_CLINT] = { 0x2000000, 0x10000 },
|
2019-10-09 02:32:07 +03:00
|
|
|
[SIFIVE_U_L2LIM] = { 0x8000000, 0x2000000 },
|
2018-03-02 15:31:14 +03:00
|
|
|
[SIFIVE_U_PLIC] = { 0xc000000, 0x4000000 },
|
2019-09-06 19:20:10 +03:00
|
|
|
[SIFIVE_U_PRCI] = { 0x10000000, 0x1000 },
|
2019-09-06 19:20:12 +03:00
|
|
|
[SIFIVE_U_UART0] = { 0x10010000, 0x1000 },
|
|
|
|
[SIFIVE_U_UART1] = { 0x10011000, 0x1000 },
|
2020-06-08 17:17:36 +03:00
|
|
|
[SIFIVE_U_GPIO] = { 0x10060000, 0x1000 },
|
2019-09-06 19:20:16 +03:00
|
|
|
[SIFIVE_U_OTP] = { 0x10070000, 0x1000 },
|
2019-09-06 19:20:17 +03:00
|
|
|
[SIFIVE_U_GEM] = { 0x10090000, 0x2000 },
|
|
|
|
[SIFIVE_U_GEM_MGMT] = { 0x100a0000, 0x1000 },
|
2020-06-16 03:50:41 +03:00
|
|
|
[SIFIVE_U_DMC] = { 0x100b0000, 0x10000 },
|
2020-06-16 03:50:40 +03:00
|
|
|
[SIFIVE_U_FLASH0] = { 0x20000000, 0x10000000 },
|
|
|
|
[SIFIVE_U_DRAM] = { 0x80000000, 0x0 },
|
2018-03-02 15:31:14 +03:00
|
|
|
};
|
|
|
|
|
2019-09-06 19:20:16 +03:00
|
|
|
#define OTP_SERIAL 1
|
2018-04-26 23:59:08 +03:00
|
|
|
#define GEM_REVISION 0x10070109
|
|
|
|
|
2019-09-06 19:19:53 +03:00
|
|
|
static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap,
|
2018-03-02 15:31:14 +03:00
|
|
|
uint64_t mem_size, const char *cmdline)
|
|
|
|
{
|
2019-09-06 19:20:06 +03:00
|
|
|
MachineState *ms = MACHINE(qdev_get_machine());
|
2018-03-02 15:31:14 +03:00
|
|
|
void *fdt;
|
|
|
|
int cpu;
|
|
|
|
uint32_t *cells;
|
|
|
|
char *nodename;
|
2019-09-06 19:20:11 +03:00
|
|
|
char ethclk_names[] = "pclk\0hclk";
|
2020-06-08 17:17:38 +03:00
|
|
|
uint32_t plic_phandle, prci_phandle, gpio_phandle, phandle = 1;
|
2019-09-06 19:20:17 +03:00
|
|
|
uint32_t hfclk_phandle, rtcclk_phandle, phy_phandle;
|
2018-03-02 15:31:14 +03:00
|
|
|
|
|
|
|
fdt = s->fdt = create_device_tree(&s->fdt_size);
|
|
|
|
if (!fdt) {
|
|
|
|
error_report("create_device_tree() failed");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
2019-09-06 19:20:19 +03:00
|
|
|
qemu_fdt_setprop_string(fdt, "/", "model", "SiFive HiFive Unleashed A00");
|
|
|
|
qemu_fdt_setprop_string(fdt, "/", "compatible",
|
|
|
|
"sifive,hifive-unleashed-a00");
|
2018-03-02 15:31:14 +03:00
|
|
|
qemu_fdt_setprop_cell(fdt, "/", "#size-cells", 0x2);
|
|
|
|
qemu_fdt_setprop_cell(fdt, "/", "#address-cells", 0x2);
|
|
|
|
|
|
|
|
qemu_fdt_add_subnode(fdt, "/soc");
|
|
|
|
qemu_fdt_setprop(fdt, "/soc", "ranges", NULL, 0);
|
2018-05-11 20:22:48 +03:00
|
|
|
qemu_fdt_setprop_string(fdt, "/soc", "compatible", "simple-bus");
|
2018-03-02 15:31:14 +03:00
|
|
|
qemu_fdt_setprop_cell(fdt, "/soc", "#size-cells", 0x2);
|
|
|
|
qemu_fdt_setprop_cell(fdt, "/soc", "#address-cells", 0x2);
|
|
|
|
|
2019-09-06 19:20:09 +03:00
|
|
|
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);
|
|
|
|
|
2018-03-02 15:31:14 +03:00
|
|
|
nodename = g_strdup_printf("/memory@%lx",
|
|
|
|
(long)memmap[SIFIVE_U_DRAM].base);
|
|
|
|
qemu_fdt_add_subnode(fdt, nodename);
|
|
|
|
qemu_fdt_setprop_cells(fdt, nodename, "reg",
|
|
|
|
memmap[SIFIVE_U_DRAM].base >> 32, memmap[SIFIVE_U_DRAM].base,
|
|
|
|
mem_size >> 32, mem_size);
|
|
|
|
qemu_fdt_setprop_string(fdt, nodename, "device_type", "memory");
|
|
|
|
g_free(nodename);
|
|
|
|
|
|
|
|
qemu_fdt_add_subnode(fdt, "/cpus");
|
2018-03-03 04:30:07 +03:00
|
|
|
qemu_fdt_setprop_cell(fdt, "/cpus", "timebase-frequency",
|
|
|
|
SIFIVE_CLINT_TIMEBASE_FREQ);
|
2018-03-02 15:31:14 +03:00
|
|
|
qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0x0);
|
|
|
|
qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 0x1);
|
|
|
|
|
2019-09-06 19:20:06 +03:00
|
|
|
for (cpu = ms->smp.cpus - 1; cpu >= 0; cpu--) {
|
2019-05-17 18:51:24 +03:00
|
|
|
int cpu_phandle = phandle++;
|
2018-03-02 15:31:14 +03:00
|
|
|
nodename = g_strdup_printf("/cpus/cpu@%d", cpu);
|
|
|
|
char *intc = g_strdup_printf("/cpus/cpu@%d/interrupt-controller", cpu);
|
2019-09-06 19:20:06 +03:00
|
|
|
char *isa;
|
2018-03-02 15:31:14 +03:00
|
|
|
qemu_fdt_add_subnode(fdt, nodename);
|
2019-09-06 19:20:06 +03:00
|
|
|
/* cpu 0 is the management hart that does not have mmu */
|
|
|
|
if (cpu != 0) {
|
2020-03-07 15:48:39 +03:00
|
|
|
#if defined(TARGET_RISCV32)
|
|
|
|
qemu_fdt_setprop_string(fdt, nodename, "mmu-type", "riscv,sv32");
|
|
|
|
#else
|
2019-09-06 19:20:06 +03:00
|
|
|
qemu_fdt_setprop_string(fdt, nodename, "mmu-type", "riscv,sv48");
|
2020-03-07 15:48:39 +03:00
|
|
|
#endif
|
2019-09-06 19:20:06 +03:00
|
|
|
isa = riscv_isa_string(&s->soc.u_cpus.harts[cpu - 1]);
|
|
|
|
} else {
|
|
|
|
isa = riscv_isa_string(&s->soc.e_cpus.harts[0]);
|
|
|
|
}
|
2018-03-02 15:31:14 +03:00
|
|
|
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");
|
|
|
|
qemu_fdt_setprop_cell(fdt, nodename, "reg", cpu);
|
|
|
|
qemu_fdt_setprop_string(fdt, nodename, "device_type", "cpu");
|
|
|
|
qemu_fdt_add_subnode(fdt, intc);
|
2019-05-17 18:51:24 +03:00
|
|
|
qemu_fdt_setprop_cell(fdt, intc, "phandle", cpu_phandle);
|
2018-03-02 15:31:14 +03:00
|
|
|
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);
|
|
|
|
g_free(isa);
|
|
|
|
g_free(intc);
|
|
|
|
g_free(nodename);
|
|
|
|
}
|
|
|
|
|
2019-09-06 19:20:06 +03:00
|
|
|
cells = g_new0(uint32_t, ms->smp.cpus * 4);
|
|
|
|
for (cpu = 0; cpu < ms->smp.cpus; cpu++) {
|
2018-03-02 15:31:14 +03:00
|
|
|
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_SOFT);
|
|
|
|
cells[cpu * 4 + 2] = cpu_to_be32(intc_phandle);
|
|
|
|
cells[cpu * 4 + 3] = cpu_to_be32(IRQ_M_TIMER);
|
|
|
|
g_free(nodename);
|
|
|
|
}
|
|
|
|
nodename = g_strdup_printf("/soc/clint@%lx",
|
|
|
|
(long)memmap[SIFIVE_U_CLINT].base);
|
|
|
|
qemu_fdt_add_subnode(fdt, nodename);
|
|
|
|
qemu_fdt_setprop_string(fdt, nodename, "compatible", "riscv,clint0");
|
|
|
|
qemu_fdt_setprop_cells(fdt, nodename, "reg",
|
|
|
|
0x0, memmap[SIFIVE_U_CLINT].base,
|
|
|
|
0x0, memmap[SIFIVE_U_CLINT].size);
|
|
|
|
qemu_fdt_setprop(fdt, nodename, "interrupts-extended",
|
2019-09-06 19:20:06 +03:00
|
|
|
cells, ms->smp.cpus * sizeof(uint32_t) * 4);
|
2018-03-02 15:31:14 +03:00
|
|
|
g_free(cells);
|
|
|
|
g_free(nodename);
|
|
|
|
|
2020-06-08 17:17:33 +03:00
|
|
|
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);
|
|
|
|
|
2019-09-06 19:20:10 +03:00
|
|
|
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);
|
|
|
|
|
2019-05-17 18:51:24 +03:00
|
|
|
plic_phandle = phandle++;
|
2019-09-06 19:20:06 +03:00
|
|
|
cells = g_new0(uint32_t, ms->smp.cpus * 4 - 2);
|
|
|
|
for (cpu = 0; cpu < ms->smp.cpus; cpu++) {
|
2018-03-02 15:31:14 +03:00
|
|
|
nodename =
|
|
|
|
g_strdup_printf("/cpus/cpu@%d/interrupt-controller", cpu);
|
|
|
|
uint32_t intc_phandle = qemu_fdt_get_phandle(fdt, nodename);
|
2019-09-06 19:20:06 +03:00
|
|
|
/* 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);
|
|
|
|
}
|
2018-03-02 15:31:14 +03:00
|
|
|
g_free(nodename);
|
|
|
|
}
|
|
|
|
nodename = g_strdup_printf("/soc/interrupt-controller@%lx",
|
|
|
|
(long)memmap[SIFIVE_U_PLIC].base);
|
|
|
|
qemu_fdt_add_subnode(fdt, nodename);
|
|
|
|
qemu_fdt_setprop_cell(fdt, nodename, "#interrupt-cells", 1);
|
|
|
|
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",
|
2019-09-06 19:20:06 +03:00
|
|
|
cells, (ms->smp.cpus * 4 - 2) * sizeof(uint32_t));
|
2018-03-02 15:31:14 +03:00
|
|
|
qemu_fdt_setprop_cells(fdt, nodename, "reg",
|
|
|
|
0x0, memmap[SIFIVE_U_PLIC].base,
|
|
|
|
0x0, memmap[SIFIVE_U_PLIC].size);
|
2018-05-11 20:24:00 +03:00
|
|
|
qemu_fdt_setprop_cell(fdt, nodename, "riscv,ndev", 0x35);
|
2019-09-06 19:19:51 +03:00
|
|
|
qemu_fdt_setprop_cell(fdt, nodename, "phandle", plic_phandle);
|
2018-03-02 15:31:14 +03:00
|
|
|
plic_phandle = qemu_fdt_get_phandle(fdt, nodename);
|
|
|
|
g_free(cells);
|
|
|
|
g_free(nodename);
|
|
|
|
|
2020-06-08 17:17:38 +03:00
|
|
|
gpio_phandle = phandle++;
|
2020-06-08 17:17:36 +03:00
|
|
|
nodename = g_strdup_printf("/soc/gpio@%lx",
|
|
|
|
(long)memmap[SIFIVE_U_GPIO].base);
|
|
|
|
qemu_fdt_add_subnode(fdt, nodename);
|
2020-06-08 17:17:38 +03:00
|
|
|
qemu_fdt_setprop_cell(fdt, nodename, "phandle", gpio_phandle);
|
2020-06-08 17:17:36 +03:00
|
|
|
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);
|
|
|
|
|
2020-06-08 17:17:38 +03:00
|
|
|
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);
|
|
|
|
|
2019-09-06 19:20:17 +03:00
|
|
|
phy_phandle = phandle++;
|
2018-04-26 23:59:08 +03:00
|
|
|
nodename = g_strdup_printf("/soc/ethernet@%lx",
|
|
|
|
(long)memmap[SIFIVE_U_GEM].base);
|
|
|
|
qemu_fdt_add_subnode(fdt, nodename);
|
2019-09-06 19:20:17 +03:00
|
|
|
qemu_fdt_setprop_string(fdt, nodename, "compatible",
|
|
|
|
"sifive,fu540-c000-gem");
|
2018-04-26 23:59:08 +03:00
|
|
|
qemu_fdt_setprop_cells(fdt, nodename, "reg",
|
|
|
|
0x0, memmap[SIFIVE_U_GEM].base,
|
2019-09-06 19:20:17 +03:00
|
|
|
0x0, memmap[SIFIVE_U_GEM].size,
|
|
|
|
0x0, memmap[SIFIVE_U_GEM_MGMT].base,
|
|
|
|
0x0, memmap[SIFIVE_U_GEM_MGMT].size);
|
2018-04-26 23:59:08 +03:00
|
|
|
qemu_fdt_setprop_string(fdt, nodename, "reg-names", "control");
|
|
|
|
qemu_fdt_setprop_string(fdt, nodename, "phy-mode", "gmii");
|
2019-09-06 19:20:17 +03:00
|
|
|
qemu_fdt_setprop_cell(fdt, nodename, "phy-handle", phy_phandle);
|
2019-09-06 19:19:51 +03:00
|
|
|
qemu_fdt_setprop_cell(fdt, nodename, "interrupt-parent", plic_phandle);
|
|
|
|
qemu_fdt_setprop_cell(fdt, nodename, "interrupts", SIFIVE_U_GEM_IRQ);
|
2018-12-13 21:34:52 +03:00
|
|
|
qemu_fdt_setprop_cells(fdt, nodename, "clocks",
|
2019-09-06 19:20:11 +03:00
|
|
|
prci_phandle, PRCI_CLK_GEMGXLPLL, prci_phandle, PRCI_CLK_GEMGXLPLL);
|
2019-07-19 16:40:45 +03:00
|
|
|
qemu_fdt_setprop(fdt, nodename, "clock-names", ethclk_names,
|
2018-12-13 21:34:52 +03:00
|
|
|
sizeof(ethclk_names));
|
2019-09-06 19:20:17 +03:00
|
|
|
qemu_fdt_setprop(fdt, nodename, "local-mac-address",
|
|
|
|
s->soc.gem.conf.macaddr.a, ETH_ALEN);
|
2019-09-06 19:19:51 +03:00
|
|
|
qemu_fdt_setprop_cell(fdt, nodename, "#address-cells", 1);
|
|
|
|
qemu_fdt_setprop_cell(fdt, nodename, "#size-cells", 0);
|
2019-09-21 08:41:31 +03:00
|
|
|
|
|
|
|
qemu_fdt_add_subnode(fdt, "/aliases");
|
|
|
|
qemu_fdt_setprop_string(fdt, "/aliases", "ethernet0", nodename);
|
|
|
|
|
2018-04-26 23:59:08 +03:00
|
|
|
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);
|
2019-09-06 19:20:17 +03:00
|
|
|
qemu_fdt_setprop_cell(fdt, nodename, "phandle", phy_phandle);
|
2019-09-06 19:19:51 +03:00
|
|
|
qemu_fdt_setprop_cell(fdt, nodename, "reg", 0x0);
|
2018-04-26 23:59:08 +03:00
|
|
|
g_free(nodename);
|
|
|
|
|
2019-09-06 19:20:13 +03:00
|
|
|
nodename = g_strdup_printf("/soc/serial@%lx",
|
2018-03-02 15:31:14 +03:00
|
|
|
(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);
|
2019-09-06 19:20:11 +03:00
|
|
|
qemu_fdt_setprop_cells(fdt, nodename, "clocks",
|
|
|
|
prci_phandle, PRCI_CLK_TLCLK);
|
2019-09-06 19:19:51 +03:00
|
|
|
qemu_fdt_setprop_cell(fdt, nodename, "interrupt-parent", plic_phandle);
|
|
|
|
qemu_fdt_setprop_cell(fdt, nodename, "interrupts", SIFIVE_U_UART0_IRQ);
|
2018-03-02 15:31:14 +03:00
|
|
|
|
|
|
|
qemu_fdt_add_subnode(fdt, "/chosen");
|
|
|
|
qemu_fdt_setprop_string(fdt, "/chosen", "stdout-path", nodename);
|
2018-05-22 04:33:28 +03:00
|
|
|
if (cmdline) {
|
|
|
|
qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", cmdline);
|
|
|
|
}
|
2019-07-19 16:40:44 +03:00
|
|
|
|
|
|
|
qemu_fdt_setprop_string(fdt, "/aliases", "serial0", nodename);
|
|
|
|
|
2018-03-02 15:31:14 +03:00
|
|
|
g_free(nodename);
|
|
|
|
}
|
|
|
|
|
2020-06-08 17:17:38 +03:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-03 01:57:22 +03:00
|
|
|
static void sifive_u_machine_init(MachineState *machine)
|
2018-03-02 15:31:14 +03:00
|
|
|
{
|
|
|
|
const struct MemmapEntry *memmap = sifive_u_memmap;
|
2019-10-09 02:32:14 +03:00
|
|
|
SiFiveUState *s = RISCV_U_MACHINE(machine);
|
2018-03-04 01:52:13 +03:00
|
|
|
MemoryRegion *system_memory = get_system_memory();
|
2018-03-02 15:31:14 +03:00
|
|
|
MemoryRegion *main_mem = g_new(MemoryRegion, 1);
|
2019-10-09 02:32:11 +03:00
|
|
|
MemoryRegion *flash0 = g_new(MemoryRegion, 1);
|
2019-10-09 02:32:18 +03:00
|
|
|
target_ulong start_addr = memmap[SIFIVE_U_DRAM].base;
|
2018-03-04 01:52:13 +03:00
|
|
|
int i;
|
2018-03-02 15:31:14 +03:00
|
|
|
|
2018-04-26 21:15:24 +03:00
|
|
|
/* Initialize SoC */
|
qom: Less verbose object_initialize_child()
All users of object_initialize_child() pass the obvious child size
argument. Almost all pass &error_abort and no properties. Tiresome.
Rename object_initialize_child() to
object_initialize_child_with_props() to free the name. New
convenience wrapper object_initialize_child() automates the size
argument, and passes &error_abort and no properties.
Rename object_initialize_childv() to
object_initialize_child_with_propsv() for consistency.
Convert callers with this Coccinelle script:
@@
expression parent, propname, type;
expression child, size;
symbol error_abort;
@@
- object_initialize_child(parent, propname, OBJECT(child), size, type, &error_abort, NULL)
+ object_initialize_child(parent, propname, child, size, type, &error_abort, NULL)
@@
expression parent, propname, type;
expression child;
symbol error_abort;
@@
- object_initialize_child(parent, propname, child, sizeof(*child), type, &error_abort, NULL)
+ object_initialize_child(parent, propname, child, type)
@@
expression parent, propname, type;
expression child;
symbol error_abort;
@@
- object_initialize_child(parent, propname, &child, sizeof(child), type, &error_abort, NULL)
+ object_initialize_child(parent, propname, &child, type)
@@
expression parent, propname, type;
expression child, size, err;
expression list props;
@@
- object_initialize_child(parent, propname, child, size, type, err, props)
+ object_initialize_child_with_props(parent, propname, child, size, type, err, props)
Note that Coccinelle chokes on ARMSSE typedef vs. macro in
hw/arm/armsse.c. Worked around by temporarily renaming the macro for
the spatch run.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Acked-by: Alistair Francis <alistair.francis@wdc.com>
[Rebased: machine opentitan is new (commit fe0fe4735e7)]
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Message-Id: <20200610053247.1583243-37-armbru@redhat.com>
2020-06-10 08:32:25 +03:00
|
|
|
object_initialize_child(OBJECT(machine), "soc", &s->soc, TYPE_RISCV_U_SOC);
|
2019-11-16 18:08:50 +03:00
|
|
|
object_property_set_uint(OBJECT(&s->soc), s->serial, "serial",
|
|
|
|
&error_abort);
|
qdev: Convert bus-less devices to qdev_realize() with Coccinelle
All remaining conversions to qdev_realize() are for bus-less devices.
Coccinelle script:
// only correct for bus-less @dev!
@@
expression errp;
expression dev;
@@
- qdev_init_nofail(dev);
+ qdev_realize(dev, NULL, &error_fatal);
@ depends on !(file in "hw/core/qdev.c") && !(file in "hw/core/bus.c")@
expression errp;
expression dev;
symbol true;
@@
- object_property_set_bool(OBJECT(dev), true, "realized", errp);
+ qdev_realize(DEVICE(dev), NULL, errp);
@ depends on !(file in "hw/core/qdev.c") && !(file in "hw/core/bus.c")@
expression errp;
expression dev;
symbol true;
@@
- object_property_set_bool(dev, true, "realized", errp);
+ qdev_realize(DEVICE(dev), NULL, errp);
Note that Coccinelle chokes on ARMSSE typedef vs. macro in
hw/arm/armsse.c. Worked around by temporarily renaming the macro for
the spatch run.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Acked-by: Alistair Francis <alistair.francis@wdc.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Message-Id: <20200610053247.1583243-57-armbru@redhat.com>
2020-06-10 08:32:45 +03:00
|
|
|
qdev_realize(DEVICE(&s->soc), NULL, &error_abort);
|
2018-03-02 15:31:14 +03:00
|
|
|
|
|
|
|
/* register RAM */
|
|
|
|
memory_region_init_ram(main_mem, NULL, "riscv.sifive.u.ram",
|
|
|
|
machine->ram_size, &error_fatal);
|
2018-03-04 01:52:13 +03:00
|
|
|
memory_region_add_subregion(system_memory, memmap[SIFIVE_U_DRAM].base,
|
2018-04-26 21:15:24 +03:00
|
|
|
main_mem);
|
2018-03-02 15:31:14 +03:00
|
|
|
|
2019-10-09 02:32:11 +03:00
|
|
|
/* register QSPI0 Flash */
|
|
|
|
memory_region_init_ram(flash0, NULL, "riscv.sifive.u.flash0",
|
|
|
|
memmap[SIFIVE_U_FLASH0].size, &error_fatal);
|
|
|
|
memory_region_add_subregion(system_memory, memmap[SIFIVE_U_FLASH0].base,
|
|
|
|
flash0);
|
|
|
|
|
2020-06-08 17:17:38 +03:00
|
|
|
/* register gpio-restart */
|
|
|
|
qdev_connect_gpio_out(DEVICE(&(s->soc.gpio)), 10,
|
|
|
|
qemu_allocate_irq(sifive_u_machine_reset, NULL, 0));
|
|
|
|
|
2018-03-02 15:31:14 +03:00
|
|
|
/* create device tree */
|
2019-09-06 19:19:53 +03:00
|
|
|
create_fdt(s, memmap, machine->ram_size, machine->kernel_cmdline);
|
2018-03-02 15:31:14 +03:00
|
|
|
|
2020-06-16 03:50:39 +03:00
|
|
|
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);
|
2019-06-25 01:11:52 +03:00
|
|
|
|
2018-03-02 15:31:14 +03:00
|
|
|
if (machine->kernel_filename) {
|
2019-11-19 09:21:09 +03:00
|
|
|
uint64_t kernel_entry = riscv_load_kernel(machine->kernel_filename,
|
|
|
|
NULL);
|
2019-07-19 16:40:43 +03:00
|
|
|
|
|
|
|
if (machine->initrd_filename) {
|
|
|
|
hwaddr start;
|
|
|
|
hwaddr end = riscv_load_initrd(machine->initrd_filename,
|
|
|
|
machine->ram_size, kernel_entry,
|
|
|
|
&start);
|
2019-09-06 19:19:53 +03:00
|
|
|
qemu_fdt_setprop_cell(s->fdt, "/chosen",
|
2019-07-19 16:40:43 +03:00
|
|
|
"linux,initrd-start", start);
|
2019-09-06 19:19:53 +03:00
|
|
|
qemu_fdt_setprop_cell(s->fdt, "/chosen", "linux,initrd-end",
|
2019-07-19 16:40:43 +03:00
|
|
|
end);
|
|
|
|
}
|
2018-03-02 15:31:14 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/* reset vector */
|
|
|
|
uint32_t reset_vec[8] = {
|
2020-06-16 03:50:39 +03:00
|
|
|
s->msel, /* MSEL pin state */
|
2018-03-02 15:31:14 +03:00
|
|
|
0x00000297, /* 1: auipc t0, %pcrel_hi(dtb) */
|
2020-06-16 03:50:38 +03:00
|
|
|
0x01c28593, /* addi a1, t0, %pcrel_lo(1b) */
|
2018-03-02 15:31:14 +03:00
|
|
|
0xf1402573, /* csrr a0, mhartid */
|
|
|
|
#if defined(TARGET_RISCV32)
|
|
|
|
0x0182a283, /* lw t0, 24(t0) */
|
|
|
|
#elif defined(TARGET_RISCV64)
|
2020-06-16 03:50:38 +03:00
|
|
|
0x0182e283, /* lwu t0, 24(t0) */
|
2018-03-02 15:31:14 +03:00
|
|
|
#endif
|
|
|
|
0x00028067, /* jr t0 */
|
|
|
|
0x00000000,
|
2019-10-09 02:32:18 +03:00
|
|
|
start_addr, /* start: .dword */
|
2018-03-02 15:31:14 +03:00
|
|
|
/* dtb: */
|
|
|
|
};
|
|
|
|
|
2018-03-04 01:52:13 +03:00
|
|
|
/* copy in the reset vector in little_endian byte order */
|
|
|
|
for (i = 0; i < sizeof(reset_vec) >> 2; i++) {
|
|
|
|
reset_vec[i] = cpu_to_le32(reset_vec[i]);
|
|
|
|
}
|
|
|
|
rom_add_blob_fixed_as("mrom.reset", reset_vec, sizeof(reset_vec),
|
|
|
|
memmap[SIFIVE_U_MROM].base, &address_space_memory);
|
2018-03-02 15:31:14 +03:00
|
|
|
|
|
|
|
/* copy in the device tree */
|
2018-03-04 01:52:13 +03:00
|
|
|
if (fdt_pack(s->fdt) || fdt_totalsize(s->fdt) >
|
|
|
|
memmap[SIFIVE_U_MROM].size - sizeof(reset_vec)) {
|
|
|
|
error_report("not enough space to store device-tree");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
qemu_fdt_dumpdtb(s->fdt, fdt_totalsize(s->fdt));
|
|
|
|
rom_add_blob_fixed_as("mrom.fdt", s->fdt, fdt_totalsize(s->fdt),
|
|
|
|
memmap[SIFIVE_U_MROM].base + sizeof(reset_vec),
|
|
|
|
&address_space_memory);
|
2018-04-26 21:15:24 +03:00
|
|
|
}
|
|
|
|
|
2020-03-03 01:57:22 +03:00
|
|
|
static bool sifive_u_machine_get_start_in_flash(Object *obj, Error **errp)
|
|
|
|
{
|
|
|
|
SiFiveUState *s = RISCV_U_MACHINE(obj);
|
|
|
|
|
|
|
|
return s->start_in_flash;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void sifive_u_machine_set_start_in_flash(Object *obj, bool value, Error **errp)
|
|
|
|
{
|
|
|
|
SiFiveUState *s = RISCV_U_MACHINE(obj);
|
|
|
|
|
|
|
|
s->start_in_flash = value;
|
|
|
|
}
|
|
|
|
|
2020-06-08 17:17:39 +03:00
|
|
|
static void sifive_u_machine_get_uint32_prop(Object *obj, Visitor *v,
|
|
|
|
const char *name, void *opaque,
|
|
|
|
Error **errp)
|
2019-11-16 18:08:50 +03:00
|
|
|
{
|
|
|
|
visit_type_uint32(v, name, (uint32_t *)opaque, errp);
|
|
|
|
}
|
|
|
|
|
2020-06-08 17:17:39 +03:00
|
|
|
static void sifive_u_machine_set_uint32_prop(Object *obj, Visitor *v,
|
|
|
|
const char *name, void *opaque,
|
|
|
|
Error **errp)
|
2019-11-16 18:08:50 +03:00
|
|
|
{
|
|
|
|
visit_type_uint32(v, name, (uint32_t *)opaque, errp);
|
|
|
|
}
|
|
|
|
|
2020-03-03 01:57:22 +03:00
|
|
|
static void sifive_u_machine_instance_init(Object *obj)
|
|
|
|
{
|
|
|
|
SiFiveUState *s = RISCV_U_MACHINE(obj);
|
|
|
|
|
|
|
|
s->start_in_flash = false;
|
qom: Drop parameter @errp of object_property_add() & friends
The only way object_property_add() can fail is when a property with
the same name already exists. Since our property names are all
hardcoded, failure is a programming error, and the appropriate way to
handle it is passing &error_abort.
Same for its variants, except for object_property_add_child(), which
additionally fails when the child already has a parent. Parentage is
also under program control, so this is a programming error, too.
We have a bit over 500 callers. Almost half of them pass
&error_abort, slightly fewer ignore errors, one test case handles
errors, and the remaining few callers pass them to their own callers.
The previous few commits demonstrated once again that ignoring
programming errors is a bad idea.
Of the few ones that pass on errors, several violate the Error API.
The Error ** argument must be NULL, &error_abort, &error_fatal, or a
pointer to a variable containing NULL. Passing an argument of the
latter kind twice without clearing it in between is wrong: if the
first call sets an error, it no longer points to NULL for the second
call. ich9_pm_add_properties(), sparc32_ledma_realize(),
sparc32_dma_realize(), xilinx_axidma_realize(), xilinx_enet_realize()
are wrong that way.
When the one appropriate choice of argument is &error_abort, letting
users pick the argument is a bad idea.
Drop parameter @errp and assert the preconditions instead.
There's one exception to "duplicate property name is a programming
error": the way object_property_add() implements the magic (and
undocumented) "automatic arrayification". Don't drop @errp there.
Instead, rename object_property_add() to object_property_try_add(),
and add the obvious wrapper object_property_add().
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Message-Id: <20200505152926.18877-15-armbru@redhat.com>
[Two semantic rebase conflicts resolved]
2020-05-05 18:29:22 +03:00
|
|
|
object_property_add_bool(obj, "start-in-flash",
|
|
|
|
sifive_u_machine_get_start_in_flash,
|
|
|
|
sifive_u_machine_set_start_in_flash);
|
2020-03-03 01:57:22 +03:00
|
|
|
object_property_set_description(obj, "start-in-flash",
|
|
|
|
"Set on to tell QEMU's ROM to jump to "
|
2020-06-16 03:50:39 +03:00
|
|
|
"flash. Otherwise QEMU will jump to DRAM "
|
|
|
|
"or L2LIM depending on the msel value");
|
2019-11-16 18:08:50 +03:00
|
|
|
|
2020-06-08 17:17:40 +03:00
|
|
|
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");
|
|
|
|
|
2019-11-16 18:08:50 +03:00
|
|
|
s->serial = OTP_SERIAL;
|
qom: Drop parameter @errp of object_property_add() & friends
The only way object_property_add() can fail is when a property with
the same name already exists. Since our property names are all
hardcoded, failure is a programming error, and the appropriate way to
handle it is passing &error_abort.
Same for its variants, except for object_property_add_child(), which
additionally fails when the child already has a parent. Parentage is
also under program control, so this is a programming error, too.
We have a bit over 500 callers. Almost half of them pass
&error_abort, slightly fewer ignore errors, one test case handles
errors, and the remaining few callers pass them to their own callers.
The previous few commits demonstrated once again that ignoring
programming errors is a bad idea.
Of the few ones that pass on errors, several violate the Error API.
The Error ** argument must be NULL, &error_abort, &error_fatal, or a
pointer to a variable containing NULL. Passing an argument of the
latter kind twice without clearing it in between is wrong: if the
first call sets an error, it no longer points to NULL for the second
call. ich9_pm_add_properties(), sparc32_ledma_realize(),
sparc32_dma_realize(), xilinx_axidma_realize(), xilinx_enet_realize()
are wrong that way.
When the one appropriate choice of argument is &error_abort, letting
users pick the argument is a bad idea.
Drop parameter @errp and assert the preconditions instead.
There's one exception to "duplicate property name is a programming
error": the way object_property_add() implements the magic (and
undocumented) "automatic arrayification". Don't drop @errp there.
Instead, rename object_property_add() to object_property_try_add(),
and add the obvious wrapper object_property_add().
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Message-Id: <20200505152926.18877-15-armbru@redhat.com>
[Two semantic rebase conflicts resolved]
2020-05-05 18:29:22 +03:00
|
|
|
object_property_add(obj, "serial", "uint32",
|
2020-06-08 17:17:39 +03:00
|
|
|
sifive_u_machine_get_uint32_prop,
|
|
|
|
sifive_u_machine_set_uint32_prop, NULL, &s->serial);
|
2020-05-05 18:29:15 +03:00
|
|
|
object_property_set_description(obj, "serial", "Board serial number");
|
2020-03-03 01:57:22 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static void sifive_u_machine_class_init(ObjectClass *oc, void *data)
|
|
|
|
{
|
|
|
|
MachineClass *mc = MACHINE_CLASS(oc);
|
|
|
|
|
|
|
|
mc->desc = "RISC-V Board compatible with SiFive U SDK";
|
|
|
|
mc->init = sifive_u_machine_init;
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const TypeInfo sifive_u_machine_typeinfo = {
|
|
|
|
.name = MACHINE_TYPE_NAME("sifive_u"),
|
|
|
|
.parent = TYPE_MACHINE,
|
|
|
|
.class_init = sifive_u_machine_class_init,
|
|
|
|
.instance_init = sifive_u_machine_instance_init,
|
|
|
|
.instance_size = sizeof(SiFiveUState),
|
|
|
|
};
|
|
|
|
|
|
|
|
static void sifive_u_machine_init_register_types(void)
|
|
|
|
{
|
|
|
|
type_register_static(&sifive_u_machine_typeinfo);
|
|
|
|
}
|
|
|
|
|
|
|
|
type_init(sifive_u_machine_init_register_types)
|
|
|
|
|
2020-05-21 17:42:26 +03:00
|
|
|
static void sifive_u_soc_instance_init(Object *obj)
|
2018-04-26 21:15:24 +03:00
|
|
|
{
|
2019-05-18 23:54:23 +03:00
|
|
|
MachineState *ms = MACHINE(qdev_get_machine());
|
2018-04-26 21:15:24 +03:00
|
|
|
SiFiveUSoCState *s = RISCV_U_SOC(obj);
|
|
|
|
|
qom: Less verbose object_initialize_child()
All users of object_initialize_child() pass the obvious child size
argument. Almost all pass &error_abort and no properties. Tiresome.
Rename object_initialize_child() to
object_initialize_child_with_props() to free the name. New
convenience wrapper object_initialize_child() automates the size
argument, and passes &error_abort and no properties.
Rename object_initialize_childv() to
object_initialize_child_with_propsv() for consistency.
Convert callers with this Coccinelle script:
@@
expression parent, propname, type;
expression child, size;
symbol error_abort;
@@
- object_initialize_child(parent, propname, OBJECT(child), size, type, &error_abort, NULL)
+ object_initialize_child(parent, propname, child, size, type, &error_abort, NULL)
@@
expression parent, propname, type;
expression child;
symbol error_abort;
@@
- object_initialize_child(parent, propname, child, sizeof(*child), type, &error_abort, NULL)
+ object_initialize_child(parent, propname, child, type)
@@
expression parent, propname, type;
expression child;
symbol error_abort;
@@
- object_initialize_child(parent, propname, &child, sizeof(child), type, &error_abort, NULL)
+ object_initialize_child(parent, propname, &child, type)
@@
expression parent, propname, type;
expression child, size, err;
expression list props;
@@
- object_initialize_child(parent, propname, child, size, type, err, props)
+ object_initialize_child_with_props(parent, propname, child, size, type, err, props)
Note that Coccinelle chokes on ARMSSE typedef vs. macro in
hw/arm/armsse.c. Worked around by temporarily renaming the macro for
the spatch run.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Acked-by: Alistair Francis <alistair.francis@wdc.com>
[Rebased: machine opentitan is new (commit fe0fe4735e7)]
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Message-Id: <20200610053247.1583243-37-armbru@redhat.com>
2020-06-10 08:32:25 +03:00
|
|
|
object_initialize_child(obj, "e-cluster", &s->e_cluster, TYPE_CPU_CLUSTER);
|
2019-09-06 19:20:06 +03:00
|
|
|
qdev_prop_set_uint32(DEVICE(&s->e_cluster), "cluster-id", 0);
|
|
|
|
|
sysbus: Convert qdev_set_parent_bus() use with Coccinelle, part 2
This is the same transformation as in the previous commit, except
sysbus_init_child_obj() and realize are too separated for the commit's
Coccinelle script to handle, typically because sysbus_init_child_obj()
is in a device's instance_init() method, and the matching realize is
in its realize() method.
Perhaps a Coccinelle wizard could make it transform that pattern, but
I'm just a bungler, and the best I can do is transforming the two
separate parts separately:
@@
expression errp;
expression child;
symbol true;
@@
- object_property_set_bool(OBJECT(child), true, "realized", errp);
+ sysbus_realize(SYS_BUS_DEVICE(child), errp);
// only correct with a matching sysbus_init_child_obj() transformation!
@@
expression errp;
expression child;
symbol true;
@@
- object_property_set_bool(child, true, "realized", errp);
+ sysbus_realize(SYS_BUS_DEVICE(child), errp);
// only correct with a matching sysbus_init_child_obj() transformation!
@@
expression child;
@@
- qdev_init_nofail(DEVICE(child));
+ sysbus_realize(SYS_BUS_DEVICE(child), &error_fatal);
// only correct with a matching sysbus_init_child_obj() transformation!
@@
expression child;
expression dev;
@@
dev = DEVICE(child);
...
- qdev_init_nofail(dev);
+ sysbus_realize(SYS_BUS_DEVICE(dev), &error_fatal);
// only correct with a matching sysbus_init_child_obj() transformation!
@@
expression child;
identifier dev;
@@
DeviceState *dev = DEVICE(child);
...
- qdev_init_nofail(dev);
+ sysbus_realize(SYS_BUS_DEVICE(dev), &error_fatal);
// only correct with a matching sysbus_init_child_obj() transformation!
@@
expression parent, name, size, type;
expression child;
symbol true;
@@
- sysbus_init_child_obj(parent, name, child, size, type);
+ sysbus_init_child_XXX(parent, name, child, size, type);
@@
expression parent, propname, type;
expression child;
@@
- sysbus_init_child_XXX(parent, propname, child, sizeof(*child), type)
+ object_initialize_child(parent, propname, child, type)
@@
expression parent, propname, type;
expression child;
@@
- sysbus_init_child_XXX(parent, propname, &child, sizeof(child), type)
+ object_initialize_child(parent, propname, &child, type)
This script is *unsound*: we need to manually verify init and realize
conversions are properly paired.
This commit has only the pairs where object_initialize_child()'s
@child and sysbus_realize()'s @dev argument text match exactly within
the same source file.
Note that Coccinelle chokes on ARMSSE typedef vs. macro in
hw/arm/armsse.c. Worked around by temporarily renaming the macro for
the spatch run.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Acked-by: Alistair Francis <alistair.francis@wdc.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Message-Id: <20200610053247.1583243-49-armbru@redhat.com>
2020-06-10 08:32:37 +03:00
|
|
|
object_initialize_child(OBJECT(&s->e_cluster), "e-cpus", &s->e_cpus,
|
|
|
|
TYPE_RISCV_HART_ARRAY);
|
2019-09-06 19:20:06 +03:00
|
|
|
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);
|
|
|
|
|
qom: Less verbose object_initialize_child()
All users of object_initialize_child() pass the obvious child size
argument. Almost all pass &error_abort and no properties. Tiresome.
Rename object_initialize_child() to
object_initialize_child_with_props() to free the name. New
convenience wrapper object_initialize_child() automates the size
argument, and passes &error_abort and no properties.
Rename object_initialize_childv() to
object_initialize_child_with_propsv() for consistency.
Convert callers with this Coccinelle script:
@@
expression parent, propname, type;
expression child, size;
symbol error_abort;
@@
- object_initialize_child(parent, propname, OBJECT(child), size, type, &error_abort, NULL)
+ object_initialize_child(parent, propname, child, size, type, &error_abort, NULL)
@@
expression parent, propname, type;
expression child;
symbol error_abort;
@@
- object_initialize_child(parent, propname, child, sizeof(*child), type, &error_abort, NULL)
+ object_initialize_child(parent, propname, child, type)
@@
expression parent, propname, type;
expression child;
symbol error_abort;
@@
- object_initialize_child(parent, propname, &child, sizeof(child), type, &error_abort, NULL)
+ object_initialize_child(parent, propname, &child, type)
@@
expression parent, propname, type;
expression child, size, err;
expression list props;
@@
- object_initialize_child(parent, propname, child, size, type, err, props)
+ object_initialize_child_with_props(parent, propname, child, size, type, err, props)
Note that Coccinelle chokes on ARMSSE typedef vs. macro in
hw/arm/armsse.c. Worked around by temporarily renaming the macro for
the spatch run.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Acked-by: Alistair Francis <alistair.francis@wdc.com>
[Rebased: machine opentitan is new (commit fe0fe4735e7)]
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Message-Id: <20200610053247.1583243-37-armbru@redhat.com>
2020-06-10 08:32:25 +03:00
|
|
|
object_initialize_child(obj, "u-cluster", &s->u_cluster, TYPE_CPU_CLUSTER);
|
2019-09-06 19:20:06 +03:00
|
|
|
qdev_prop_set_uint32(DEVICE(&s->u_cluster), "cluster-id", 1);
|
|
|
|
|
sysbus: Convert qdev_set_parent_bus() use with Coccinelle, part 2
This is the same transformation as in the previous commit, except
sysbus_init_child_obj() and realize are too separated for the commit's
Coccinelle script to handle, typically because sysbus_init_child_obj()
is in a device's instance_init() method, and the matching realize is
in its realize() method.
Perhaps a Coccinelle wizard could make it transform that pattern, but
I'm just a bungler, and the best I can do is transforming the two
separate parts separately:
@@
expression errp;
expression child;
symbol true;
@@
- object_property_set_bool(OBJECT(child), true, "realized", errp);
+ sysbus_realize(SYS_BUS_DEVICE(child), errp);
// only correct with a matching sysbus_init_child_obj() transformation!
@@
expression errp;
expression child;
symbol true;
@@
- object_property_set_bool(child, true, "realized", errp);
+ sysbus_realize(SYS_BUS_DEVICE(child), errp);
// only correct with a matching sysbus_init_child_obj() transformation!
@@
expression child;
@@
- qdev_init_nofail(DEVICE(child));
+ sysbus_realize(SYS_BUS_DEVICE(child), &error_fatal);
// only correct with a matching sysbus_init_child_obj() transformation!
@@
expression child;
expression dev;
@@
dev = DEVICE(child);
...
- qdev_init_nofail(dev);
+ sysbus_realize(SYS_BUS_DEVICE(dev), &error_fatal);
// only correct with a matching sysbus_init_child_obj() transformation!
@@
expression child;
identifier dev;
@@
DeviceState *dev = DEVICE(child);
...
- qdev_init_nofail(dev);
+ sysbus_realize(SYS_BUS_DEVICE(dev), &error_fatal);
// only correct with a matching sysbus_init_child_obj() transformation!
@@
expression parent, name, size, type;
expression child;
symbol true;
@@
- sysbus_init_child_obj(parent, name, child, size, type);
+ sysbus_init_child_XXX(parent, name, child, size, type);
@@
expression parent, propname, type;
expression child;
@@
- sysbus_init_child_XXX(parent, propname, child, sizeof(*child), type)
+ object_initialize_child(parent, propname, child, type)
@@
expression parent, propname, type;
expression child;
@@
- sysbus_init_child_XXX(parent, propname, &child, sizeof(child), type)
+ object_initialize_child(parent, propname, &child, type)
This script is *unsound*: we need to manually verify init and realize
conversions are properly paired.
This commit has only the pairs where object_initialize_child()'s
@child and sysbus_realize()'s @dev argument text match exactly within
the same source file.
Note that Coccinelle chokes on ARMSSE typedef vs. macro in
hw/arm/armsse.c. Worked around by temporarily renaming the macro for
the spatch run.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Acked-by: Alistair Francis <alistair.francis@wdc.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Message-Id: <20200610053247.1583243-49-armbru@redhat.com>
2020-06-10 08:32:37 +03:00
|
|
|
object_initialize_child(OBJECT(&s->u_cluster), "u-cpus", &s->u_cpus,
|
|
|
|
TYPE_RISCV_HART_ARRAY);
|
2019-09-06 19:20:06 +03:00
|
|
|
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);
|
2018-04-26 23:59:08 +03:00
|
|
|
|
sysbus: Convert qdev_set_parent_bus() use with Coccinelle, part 2
This is the same transformation as in the previous commit, except
sysbus_init_child_obj() and realize are too separated for the commit's
Coccinelle script to handle, typically because sysbus_init_child_obj()
is in a device's instance_init() method, and the matching realize is
in its realize() method.
Perhaps a Coccinelle wizard could make it transform that pattern, but
I'm just a bungler, and the best I can do is transforming the two
separate parts separately:
@@
expression errp;
expression child;
symbol true;
@@
- object_property_set_bool(OBJECT(child), true, "realized", errp);
+ sysbus_realize(SYS_BUS_DEVICE(child), errp);
// only correct with a matching sysbus_init_child_obj() transformation!
@@
expression errp;
expression child;
symbol true;
@@
- object_property_set_bool(child, true, "realized", errp);
+ sysbus_realize(SYS_BUS_DEVICE(child), errp);
// only correct with a matching sysbus_init_child_obj() transformation!
@@
expression child;
@@
- qdev_init_nofail(DEVICE(child));
+ sysbus_realize(SYS_BUS_DEVICE(child), &error_fatal);
// only correct with a matching sysbus_init_child_obj() transformation!
@@
expression child;
expression dev;
@@
dev = DEVICE(child);
...
- qdev_init_nofail(dev);
+ sysbus_realize(SYS_BUS_DEVICE(dev), &error_fatal);
// only correct with a matching sysbus_init_child_obj() transformation!
@@
expression child;
identifier dev;
@@
DeviceState *dev = DEVICE(child);
...
- qdev_init_nofail(dev);
+ sysbus_realize(SYS_BUS_DEVICE(dev), &error_fatal);
// only correct with a matching sysbus_init_child_obj() transformation!
@@
expression parent, name, size, type;
expression child;
symbol true;
@@
- sysbus_init_child_obj(parent, name, child, size, type);
+ sysbus_init_child_XXX(parent, name, child, size, type);
@@
expression parent, propname, type;
expression child;
@@
- sysbus_init_child_XXX(parent, propname, child, sizeof(*child), type)
+ object_initialize_child(parent, propname, child, type)
@@
expression parent, propname, type;
expression child;
@@
- sysbus_init_child_XXX(parent, propname, &child, sizeof(child), type)
+ object_initialize_child(parent, propname, &child, type)
This script is *unsound*: we need to manually verify init and realize
conversions are properly paired.
This commit has only the pairs where object_initialize_child()'s
@child and sysbus_realize()'s @dev argument text match exactly within
the same source file.
Note that Coccinelle chokes on ARMSSE typedef vs. macro in
hw/arm/armsse.c. Worked around by temporarily renaming the macro for
the spatch run.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Acked-by: Alistair Francis <alistair.francis@wdc.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Message-Id: <20200610053247.1583243-49-armbru@redhat.com>
2020-06-10 08:32:37 +03:00
|
|
|
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);
|
2020-06-08 17:17:36 +03:00
|
|
|
object_initialize_child(obj, "gpio", &s->gpio, TYPE_SIFIVE_GPIO);
|
2018-04-26 21:15:24 +03:00
|
|
|
}
|
|
|
|
|
2020-05-21 17:42:26 +03:00
|
|
|
static void sifive_u_soc_realize(DeviceState *dev, Error **errp)
|
2018-04-26 21:15:24 +03:00
|
|
|
{
|
2019-05-18 23:54:23 +03:00
|
|
|
MachineState *ms = MACHINE(qdev_get_machine());
|
2018-04-26 21:15:24 +03:00
|
|
|
SiFiveUSoCState *s = RISCV_U_SOC(dev);
|
|
|
|
const struct MemmapEntry *memmap = sifive_u_memmap;
|
|
|
|
MemoryRegion *system_memory = get_system_memory();
|
|
|
|
MemoryRegion *mask_rom = g_new(MemoryRegion, 1);
|
2019-10-09 02:32:07 +03:00
|
|
|
MemoryRegion *l2lim_mem = g_new(MemoryRegion, 1);
|
2019-05-17 18:51:25 +03:00
|
|
|
char *plic_hart_config;
|
|
|
|
size_t plic_hart_config_len;
|
2018-04-26 23:59:08 +03:00
|
|
|
int i;
|
|
|
|
Error *err = NULL;
|
|
|
|
NICInfo *nd = &nd_table[0];
|
2018-04-26 21:15:24 +03:00
|
|
|
|
sysbus: Convert qdev_set_parent_bus() use with Coccinelle, part 2
This is the same transformation as in the previous commit, except
sysbus_init_child_obj() and realize are too separated for the commit's
Coccinelle script to handle, typically because sysbus_init_child_obj()
is in a device's instance_init() method, and the matching realize is
in its realize() method.
Perhaps a Coccinelle wizard could make it transform that pattern, but
I'm just a bungler, and the best I can do is transforming the two
separate parts separately:
@@
expression errp;
expression child;
symbol true;
@@
- object_property_set_bool(OBJECT(child), true, "realized", errp);
+ sysbus_realize(SYS_BUS_DEVICE(child), errp);
// only correct with a matching sysbus_init_child_obj() transformation!
@@
expression errp;
expression child;
symbol true;
@@
- object_property_set_bool(child, true, "realized", errp);
+ sysbus_realize(SYS_BUS_DEVICE(child), errp);
// only correct with a matching sysbus_init_child_obj() transformation!
@@
expression child;
@@
- qdev_init_nofail(DEVICE(child));
+ sysbus_realize(SYS_BUS_DEVICE(child), &error_fatal);
// only correct with a matching sysbus_init_child_obj() transformation!
@@
expression child;
expression dev;
@@
dev = DEVICE(child);
...
- qdev_init_nofail(dev);
+ sysbus_realize(SYS_BUS_DEVICE(dev), &error_fatal);
// only correct with a matching sysbus_init_child_obj() transformation!
@@
expression child;
identifier dev;
@@
DeviceState *dev = DEVICE(child);
...
- qdev_init_nofail(dev);
+ sysbus_realize(SYS_BUS_DEVICE(dev), &error_fatal);
// only correct with a matching sysbus_init_child_obj() transformation!
@@
expression parent, name, size, type;
expression child;
symbol true;
@@
- sysbus_init_child_obj(parent, name, child, size, type);
+ sysbus_init_child_XXX(parent, name, child, size, type);
@@
expression parent, propname, type;
expression child;
@@
- sysbus_init_child_XXX(parent, propname, child, sizeof(*child), type)
+ object_initialize_child(parent, propname, child, type)
@@
expression parent, propname, type;
expression child;
@@
- sysbus_init_child_XXX(parent, propname, &child, sizeof(child), type)
+ object_initialize_child(parent, propname, &child, type)
This script is *unsound*: we need to manually verify init and realize
conversions are properly paired.
This commit has only the pairs where object_initialize_child()'s
@child and sysbus_realize()'s @dev argument text match exactly within
the same source file.
Note that Coccinelle chokes on ARMSSE typedef vs. macro in
hw/arm/armsse.c. Worked around by temporarily renaming the macro for
the spatch run.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Acked-by: Alistair Francis <alistair.francis@wdc.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Message-Id: <20200610053247.1583243-49-armbru@redhat.com>
2020-06-10 08:32:37 +03:00
|
|
|
sysbus_realize(SYS_BUS_DEVICE(&s->e_cpus), &error_abort);
|
|
|
|
sysbus_realize(SYS_BUS_DEVICE(&s->u_cpus), &error_abort);
|
2019-09-06 19:20:06 +03:00
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
qdev: Convert bus-less devices to qdev_realize() with Coccinelle
All remaining conversions to qdev_realize() are for bus-less devices.
Coccinelle script:
// only correct for bus-less @dev!
@@
expression errp;
expression dev;
@@
- qdev_init_nofail(dev);
+ qdev_realize(dev, NULL, &error_fatal);
@ depends on !(file in "hw/core/qdev.c") && !(file in "hw/core/bus.c")@
expression errp;
expression dev;
symbol true;
@@
- object_property_set_bool(OBJECT(dev), true, "realized", errp);
+ qdev_realize(DEVICE(dev), NULL, errp);
@ depends on !(file in "hw/core/qdev.c") && !(file in "hw/core/bus.c")@
expression errp;
expression dev;
symbol true;
@@
- object_property_set_bool(dev, true, "realized", errp);
+ qdev_realize(DEVICE(dev), NULL, errp);
Note that Coccinelle chokes on ARMSSE typedef vs. macro in
hw/arm/armsse.c. Worked around by temporarily renaming the macro for
the spatch run.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Acked-by: Alistair Francis <alistair.francis@wdc.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Message-Id: <20200610053247.1583243-57-armbru@redhat.com>
2020-06-10 08:32:45 +03:00
|
|
|
qdev_realize(DEVICE(&s->e_cluster), NULL, &error_abort);
|
|
|
|
qdev_realize(DEVICE(&s->u_cluster), NULL, &error_abort);
|
2018-04-26 21:15:24 +03:00
|
|
|
|
|
|
|
/* boot rom */
|
2020-02-22 20:12:57 +03:00
|
|
|
memory_region_init_rom(mask_rom, OBJECT(dev), "riscv.sifive.u.mrom",
|
2018-04-26 21:15:24 +03:00
|
|
|
memmap[SIFIVE_U_MROM].size, &error_fatal);
|
|
|
|
memory_region_add_subregion(system_memory, memmap[SIFIVE_U_MROM].base,
|
|
|
|
mask_rom);
|
2018-03-02 15:31:14 +03:00
|
|
|
|
2019-10-09 02:32:07 +03:00
|
|
|
/*
|
|
|
|
* Add L2-LIM at reset size.
|
|
|
|
* This should be reduced in size as the L2 Cache Controller WayEnable
|
|
|
|
* register is incremented. Unfortunately I don't see a nice (or any) way
|
|
|
|
* to handle reducing or blocking out the L2 LIM while still allowing it
|
|
|
|
* be re returned to all enabled after a reset. For the time being, just
|
|
|
|
* leave it enabled all the time. This won't break anything, but will be
|
|
|
|
* too generous to misbehaving guests.
|
|
|
|
*/
|
|
|
|
memory_region_init_ram(l2lim_mem, NULL, "riscv.sifive.u.l2lim",
|
|
|
|
memmap[SIFIVE_U_L2LIM].size, &error_fatal);
|
|
|
|
memory_region_add_subregion(system_memory, memmap[SIFIVE_U_L2LIM].base,
|
|
|
|
l2lim_mem);
|
|
|
|
|
2019-05-17 18:51:25 +03:00
|
|
|
/* create PLIC hart topology configuration string */
|
2019-05-18 23:54:23 +03:00
|
|
|
plic_hart_config_len = (strlen(SIFIVE_U_PLIC_HART_CONFIG) + 1) *
|
|
|
|
ms->smp.cpus;
|
2019-05-17 18:51:25 +03:00
|
|
|
plic_hart_config = g_malloc0(plic_hart_config_len);
|
2019-05-18 23:54:23 +03:00
|
|
|
for (i = 0; i < ms->smp.cpus; i++) {
|
2019-05-17 18:51:25 +03:00
|
|
|
if (i != 0) {
|
2019-09-06 19:20:07 +03:00
|
|
|
strncat(plic_hart_config, "," SIFIVE_U_PLIC_HART_CONFIG,
|
|
|
|
plic_hart_config_len);
|
|
|
|
} else {
|
|
|
|
strncat(plic_hart_config, "M", plic_hart_config_len);
|
2019-05-17 18:51:25 +03:00
|
|
|
}
|
|
|
|
plic_hart_config_len -= (strlen(SIFIVE_U_PLIC_HART_CONFIG) + 1);
|
|
|
|
}
|
|
|
|
|
2018-03-02 15:31:14 +03:00
|
|
|
/* MMIO */
|
|
|
|
s->plic = sifive_plic_create(memmap[SIFIVE_U_PLIC].base,
|
2019-05-17 18:51:25 +03:00
|
|
|
plic_hart_config,
|
2018-03-02 15:31:14 +03:00
|
|
|
SIFIVE_U_PLIC_NUM_SOURCES,
|
|
|
|
SIFIVE_U_PLIC_NUM_PRIORITIES,
|
|
|
|
SIFIVE_U_PLIC_PRIORITY_BASE,
|
|
|
|
SIFIVE_U_PLIC_PENDING_BASE,
|
|
|
|
SIFIVE_U_PLIC_ENABLE_BASE,
|
|
|
|
SIFIVE_U_PLIC_ENABLE_STRIDE,
|
|
|
|
SIFIVE_U_PLIC_CONTEXT_BASE,
|
|
|
|
SIFIVE_U_PLIC_CONTEXT_STRIDE,
|
|
|
|
memmap[SIFIVE_U_PLIC].size);
|
2019-12-10 10:14:37 +03:00
|
|
|
g_free(plic_hart_config);
|
2018-03-04 01:52:13 +03:00
|
|
|
sifive_uart_create(system_memory, memmap[SIFIVE_U_UART0].base,
|
2018-04-26 23:54:12 +03:00
|
|
|
serial_hd(0), qdev_get_gpio_in(DEVICE(s->plic), SIFIVE_U_UART0_IRQ));
|
2018-12-14 03:19:03 +03:00
|
|
|
sifive_uart_create(system_memory, memmap[SIFIVE_U_UART1].base,
|
|
|
|
serial_hd(1), qdev_get_gpio_in(DEVICE(s->plic), SIFIVE_U_UART1_IRQ));
|
2018-03-02 15:31:14 +03:00
|
|
|
sifive_clint_create(memmap[SIFIVE_U_CLINT].base,
|
2019-05-18 23:54:23 +03:00
|
|
|
memmap[SIFIVE_U_CLINT].size, ms->smp.cpus,
|
2020-02-02 16:42:17 +03:00
|
|
|
SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE, false);
|
2018-04-26 23:59:08 +03:00
|
|
|
|
sysbus: Convert qdev_set_parent_bus() use with Coccinelle, part 2
This is the same transformation as in the previous commit, except
sysbus_init_child_obj() and realize are too separated for the commit's
Coccinelle script to handle, typically because sysbus_init_child_obj()
is in a device's instance_init() method, and the matching realize is
in its realize() method.
Perhaps a Coccinelle wizard could make it transform that pattern, but
I'm just a bungler, and the best I can do is transforming the two
separate parts separately:
@@
expression errp;
expression child;
symbol true;
@@
- object_property_set_bool(OBJECT(child), true, "realized", errp);
+ sysbus_realize(SYS_BUS_DEVICE(child), errp);
// only correct with a matching sysbus_init_child_obj() transformation!
@@
expression errp;
expression child;
symbol true;
@@
- object_property_set_bool(child, true, "realized", errp);
+ sysbus_realize(SYS_BUS_DEVICE(child), errp);
// only correct with a matching sysbus_init_child_obj() transformation!
@@
expression child;
@@
- qdev_init_nofail(DEVICE(child));
+ sysbus_realize(SYS_BUS_DEVICE(child), &error_fatal);
// only correct with a matching sysbus_init_child_obj() transformation!
@@
expression child;
expression dev;
@@
dev = DEVICE(child);
...
- qdev_init_nofail(dev);
+ sysbus_realize(SYS_BUS_DEVICE(dev), &error_fatal);
// only correct with a matching sysbus_init_child_obj() transformation!
@@
expression child;
identifier dev;
@@
DeviceState *dev = DEVICE(child);
...
- qdev_init_nofail(dev);
+ sysbus_realize(SYS_BUS_DEVICE(dev), &error_fatal);
// only correct with a matching sysbus_init_child_obj() transformation!
@@
expression parent, name, size, type;
expression child;
symbol true;
@@
- sysbus_init_child_obj(parent, name, child, size, type);
+ sysbus_init_child_XXX(parent, name, child, size, type);
@@
expression parent, propname, type;
expression child;
@@
- sysbus_init_child_XXX(parent, propname, child, sizeof(*child), type)
+ object_initialize_child(parent, propname, child, type)
@@
expression parent, propname, type;
expression child;
@@
- sysbus_init_child_XXX(parent, propname, &child, sizeof(child), type)
+ object_initialize_child(parent, propname, &child, type)
This script is *unsound*: we need to manually verify init and realize
conversions are properly paired.
This commit has only the pairs where object_initialize_child()'s
@child and sysbus_realize()'s @dev argument text match exactly within
the same source file.
Note that Coccinelle chokes on ARMSSE typedef vs. macro in
hw/arm/armsse.c. Worked around by temporarily renaming the macro for
the spatch run.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Acked-by: Alistair Francis <alistair.francis@wdc.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Message-Id: <20200610053247.1583243-49-armbru@redhat.com>
2020-06-10 08:32:37 +03:00
|
|
|
sysbus_realize(SYS_BUS_DEVICE(&s->prci), &err);
|
2019-09-06 19:20:10 +03:00
|
|
|
sysbus_mmio_map(SYS_BUS_DEVICE(&s->prci), 0, memmap[SIFIVE_U_PRCI].base);
|
|
|
|
|
2020-06-08 17:17:36 +03:00
|
|
|
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));
|
|
|
|
}
|
|
|
|
|
2020-03-03 02:08:51 +03:00
|
|
|
qdev_prop_set_uint32(DEVICE(&s->otp), "serial", s->serial);
|
sysbus: Convert qdev_set_parent_bus() use with Coccinelle, part 2
This is the same transformation as in the previous commit, except
sysbus_init_child_obj() and realize are too separated for the commit's
Coccinelle script to handle, typically because sysbus_init_child_obj()
is in a device's instance_init() method, and the matching realize is
in its realize() method.
Perhaps a Coccinelle wizard could make it transform that pattern, but
I'm just a bungler, and the best I can do is transforming the two
separate parts separately:
@@
expression errp;
expression child;
symbol true;
@@
- object_property_set_bool(OBJECT(child), true, "realized", errp);
+ sysbus_realize(SYS_BUS_DEVICE(child), errp);
// only correct with a matching sysbus_init_child_obj() transformation!
@@
expression errp;
expression child;
symbol true;
@@
- object_property_set_bool(child, true, "realized", errp);
+ sysbus_realize(SYS_BUS_DEVICE(child), errp);
// only correct with a matching sysbus_init_child_obj() transformation!
@@
expression child;
@@
- qdev_init_nofail(DEVICE(child));
+ sysbus_realize(SYS_BUS_DEVICE(child), &error_fatal);
// only correct with a matching sysbus_init_child_obj() transformation!
@@
expression child;
expression dev;
@@
dev = DEVICE(child);
...
- qdev_init_nofail(dev);
+ sysbus_realize(SYS_BUS_DEVICE(dev), &error_fatal);
// only correct with a matching sysbus_init_child_obj() transformation!
@@
expression child;
identifier dev;
@@
DeviceState *dev = DEVICE(child);
...
- qdev_init_nofail(dev);
+ sysbus_realize(SYS_BUS_DEVICE(dev), &error_fatal);
// only correct with a matching sysbus_init_child_obj() transformation!
@@
expression parent, name, size, type;
expression child;
symbol true;
@@
- sysbus_init_child_obj(parent, name, child, size, type);
+ sysbus_init_child_XXX(parent, name, child, size, type);
@@
expression parent, propname, type;
expression child;
@@
- sysbus_init_child_XXX(parent, propname, child, sizeof(*child), type)
+ object_initialize_child(parent, propname, child, type)
@@
expression parent, propname, type;
expression child;
@@
- sysbus_init_child_XXX(parent, propname, &child, sizeof(child), type)
+ object_initialize_child(parent, propname, &child, type)
This script is *unsound*: we need to manually verify init and realize
conversions are properly paired.
This commit has only the pairs where object_initialize_child()'s
@child and sysbus_realize()'s @dev argument text match exactly within
the same source file.
Note that Coccinelle chokes on ARMSSE typedef vs. macro in
hw/arm/armsse.c. Worked around by temporarily renaming the macro for
the spatch run.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Acked-by: Alistair Francis <alistair.francis@wdc.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Message-Id: <20200610053247.1583243-49-armbru@redhat.com>
2020-06-10 08:32:37 +03:00
|
|
|
sysbus_realize(SYS_BUS_DEVICE(&s->otp), &err);
|
2019-09-06 19:20:16 +03:00
|
|
|
sysbus_mmio_map(SYS_BUS_DEVICE(&s->otp), 0, memmap[SIFIVE_U_OTP].base);
|
|
|
|
|
2018-04-26 23:59:08 +03:00
|
|
|
if (nd->used) {
|
|
|
|
qemu_check_nic_model(nd, TYPE_CADENCE_GEM);
|
|
|
|
qdev_set_nic_properties(DEVICE(&s->gem), nd);
|
|
|
|
}
|
|
|
|
object_property_set_int(OBJECT(&s->gem), GEM_REVISION, "revision",
|
|
|
|
&error_abort);
|
sysbus: Convert qdev_set_parent_bus() use with Coccinelle, part 2
This is the same transformation as in the previous commit, except
sysbus_init_child_obj() and realize are too separated for the commit's
Coccinelle script to handle, typically because sysbus_init_child_obj()
is in a device's instance_init() method, and the matching realize is
in its realize() method.
Perhaps a Coccinelle wizard could make it transform that pattern, but
I'm just a bungler, and the best I can do is transforming the two
separate parts separately:
@@
expression errp;
expression child;
symbol true;
@@
- object_property_set_bool(OBJECT(child), true, "realized", errp);
+ sysbus_realize(SYS_BUS_DEVICE(child), errp);
// only correct with a matching sysbus_init_child_obj() transformation!
@@
expression errp;
expression child;
symbol true;
@@
- object_property_set_bool(child, true, "realized", errp);
+ sysbus_realize(SYS_BUS_DEVICE(child), errp);
// only correct with a matching sysbus_init_child_obj() transformation!
@@
expression child;
@@
- qdev_init_nofail(DEVICE(child));
+ sysbus_realize(SYS_BUS_DEVICE(child), &error_fatal);
// only correct with a matching sysbus_init_child_obj() transformation!
@@
expression child;
expression dev;
@@
dev = DEVICE(child);
...
- qdev_init_nofail(dev);
+ sysbus_realize(SYS_BUS_DEVICE(dev), &error_fatal);
// only correct with a matching sysbus_init_child_obj() transformation!
@@
expression child;
identifier dev;
@@
DeviceState *dev = DEVICE(child);
...
- qdev_init_nofail(dev);
+ sysbus_realize(SYS_BUS_DEVICE(dev), &error_fatal);
// only correct with a matching sysbus_init_child_obj() transformation!
@@
expression parent, name, size, type;
expression child;
symbol true;
@@
- sysbus_init_child_obj(parent, name, child, size, type);
+ sysbus_init_child_XXX(parent, name, child, size, type);
@@
expression parent, propname, type;
expression child;
@@
- sysbus_init_child_XXX(parent, propname, child, sizeof(*child), type)
+ object_initialize_child(parent, propname, child, type)
@@
expression parent, propname, type;
expression child;
@@
- sysbus_init_child_XXX(parent, propname, &child, sizeof(child), type)
+ object_initialize_child(parent, propname, &child, type)
This script is *unsound*: we need to manually verify init and realize
conversions are properly paired.
This commit has only the pairs where object_initialize_child()'s
@child and sysbus_realize()'s @dev argument text match exactly within
the same source file.
Note that Coccinelle chokes on ARMSSE typedef vs. macro in
hw/arm/armsse.c. Worked around by temporarily renaming the macro for
the spatch run.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Acked-by: Alistair Francis <alistair.francis@wdc.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Message-Id: <20200610053247.1583243-49-armbru@redhat.com>
2020-06-10 08:32:37 +03:00
|
|
|
sysbus_realize(SYS_BUS_DEVICE(&s->gem), &err);
|
2018-04-26 23:59:08 +03:00
|
|
|
if (err) {
|
|
|
|
error_propagate(errp, err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
sysbus_mmio_map(SYS_BUS_DEVICE(&s->gem), 0, memmap[SIFIVE_U_GEM].base);
|
|
|
|
sysbus_connect_irq(SYS_BUS_DEVICE(&s->gem), 0,
|
2020-06-08 17:17:32 +03:00
|
|
|
qdev_get_gpio_in(DEVICE(s->plic), SIFIVE_U_GEM_IRQ));
|
2019-09-06 19:20:17 +03:00
|
|
|
|
|
|
|
create_unimplemented_device("riscv.sifive.u.gem-mgmt",
|
|
|
|
memmap[SIFIVE_U_GEM_MGMT].base, memmap[SIFIVE_U_GEM_MGMT].size);
|
2020-06-16 03:50:41 +03:00
|
|
|
|
|
|
|
create_unimplemented_device("riscv.sifive.u.dmc",
|
|
|
|
memmap[SIFIVE_U_DMC].base, memmap[SIFIVE_U_DMC].size);
|
2018-03-02 15:31:14 +03:00
|
|
|
}
|
|
|
|
|
2020-05-21 17:42:26 +03:00
|
|
|
static Property sifive_u_soc_props[] = {
|
2020-03-03 02:08:51 +03:00
|
|
|
DEFINE_PROP_UINT32("serial", SiFiveUSoCState, serial, OTP_SERIAL),
|
|
|
|
DEFINE_PROP_END_OF_LIST()
|
|
|
|
};
|
|
|
|
|
2020-05-21 17:42:26 +03:00
|
|
|
static void sifive_u_soc_class_init(ObjectClass *oc, void *data)
|
2018-04-26 21:15:24 +03:00
|
|
|
{
|
|
|
|
DeviceClass *dc = DEVICE_CLASS(oc);
|
|
|
|
|
2020-05-21 17:42:26 +03:00
|
|
|
device_class_set_props(dc, sifive_u_soc_props);
|
|
|
|
dc->realize = sifive_u_soc_realize;
|
2018-04-26 21:15:24 +03:00
|
|
|
/* Reason: Uses serial_hds in realize function, thus can't be used twice */
|
|
|
|
dc->user_creatable = false;
|
|
|
|
}
|
|
|
|
|
2020-05-21 17:42:26 +03:00
|
|
|
static const TypeInfo sifive_u_soc_type_info = {
|
2018-04-26 21:15:24 +03:00
|
|
|
.name = TYPE_RISCV_U_SOC,
|
|
|
|
.parent = TYPE_DEVICE,
|
|
|
|
.instance_size = sizeof(SiFiveUSoCState),
|
2020-05-21 17:42:26 +03:00
|
|
|
.instance_init = sifive_u_soc_instance_init,
|
|
|
|
.class_init = sifive_u_soc_class_init,
|
2018-04-26 21:15:24 +03:00
|
|
|
};
|
|
|
|
|
2020-05-21 17:42:26 +03:00
|
|
|
static void sifive_u_soc_register_types(void)
|
2018-04-26 21:15:24 +03:00
|
|
|
{
|
2020-05-21 17:42:26 +03:00
|
|
|
type_register_static(&sifive_u_soc_type_info);
|
2018-04-26 21:15:24 +03:00
|
|
|
}
|
|
|
|
|
2020-05-21 17:42:26 +03:00
|
|
|
type_init(sifive_u_soc_register_types)
|