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
|
2020-09-01 04:39:11 +03:00
|
|
|
* 7) DMA (Direct Memory Access Controller)
|
2021-01-26 09:00:02 +03:00
|
|
|
* 8) SPI0 connected to an SPI flash
|
2021-01-26 09:00:03 +03:00
|
|
|
* 9) SPI2 connected to an SD card
|
2021-09-09 06:55:15 +03:00
|
|
|
* 10) PWM0 and PWM1
|
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/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"
|
2021-11-17 19:33:57 +03:00
|
|
|
#include "hw/sd/sd.h"
|
2021-01-26 09:00:02 +03:00
|
|
|
#include "hw/ssi/ssi.h"
|
2018-03-02 15:31:14 +03:00
|
|
|
#include "target/riscv/cpu.h"
|
|
|
|
#include "hw/riscv/riscv_hart.h"
|
|
|
|
#include "hw/riscv/sifive_u.h"
|
2019-06-25 01:11:49 +03:00
|
|
|
#include "hw/riscv/boot.h"
|
2020-09-03 13:40:19 +03:00
|
|
|
#include "hw/char/sifive_uart.h"
|
2021-08-31 14:06:00 +03:00
|
|
|
#include "hw/intc/riscv_aclint.h"
|
2020-09-03 13:40:17 +03:00
|
|
|
#include "hw/intc/sifive_plic.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/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
|
|
|
|
2018-03-04 01:52:13 +03:00
|
|
|
#include <libfdt.h>
|
|
|
|
|
2021-07-06 13:26:16 +03:00
|
|
|
/* CLINT timebase frequency */
|
|
|
|
#define CLINT_TIMEBASE_FREQ 1000000
|
|
|
|
|
2021-02-20 17:48:04 +03:00
|
|
|
static const MemMapEntry sifive_u_memmap[] = {
|
2020-09-11 20:34:47 +03:00
|
|
|
[SIFIVE_U_DEV_DEBUG] = { 0x0, 0x100 },
|
|
|
|
[SIFIVE_U_DEV_MROM] = { 0x1000, 0xf000 },
|
|
|
|
[SIFIVE_U_DEV_CLINT] = { 0x2000000, 0x10000 },
|
|
|
|
[SIFIVE_U_DEV_L2CC] = { 0x2010000, 0x1000 },
|
|
|
|
[SIFIVE_U_DEV_PDMA] = { 0x3000000, 0x100000 },
|
|
|
|
[SIFIVE_U_DEV_L2LIM] = { 0x8000000, 0x2000000 },
|
|
|
|
[SIFIVE_U_DEV_PLIC] = { 0xc000000, 0x4000000 },
|
|
|
|
[SIFIVE_U_DEV_PRCI] = { 0x10000000, 0x1000 },
|
|
|
|
[SIFIVE_U_DEV_UART0] = { 0x10010000, 0x1000 },
|
|
|
|
[SIFIVE_U_DEV_UART1] = { 0x10011000, 0x1000 },
|
2021-09-09 06:55:15 +03:00
|
|
|
[SIFIVE_U_DEV_PWM0] = { 0x10020000, 0x1000 },
|
|
|
|
[SIFIVE_U_DEV_PWM1] = { 0x10021000, 0x1000 },
|
2021-01-26 09:00:02 +03:00
|
|
|
[SIFIVE_U_DEV_QSPI0] = { 0x10040000, 0x1000 },
|
2021-01-26 09:00:03 +03:00
|
|
|
[SIFIVE_U_DEV_QSPI2] = { 0x10050000, 0x1000 },
|
2020-09-11 20:34:47 +03:00
|
|
|
[SIFIVE_U_DEV_GPIO] = { 0x10060000, 0x1000 },
|
|
|
|
[SIFIVE_U_DEV_OTP] = { 0x10070000, 0x1000 },
|
|
|
|
[SIFIVE_U_DEV_GEM] = { 0x10090000, 0x2000 },
|
|
|
|
[SIFIVE_U_DEV_GEM_MGMT] = { 0x100a0000, 0x1000 },
|
|
|
|
[SIFIVE_U_DEV_DMC] = { 0x100b0000, 0x10000 },
|
|
|
|
[SIFIVE_U_DEV_FLASH0] = { 0x20000000, 0x10000000 },
|
|
|
|
[SIFIVE_U_DEV_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
|
|
|
|
|
2021-02-20 17:48:04 +03:00
|
|
|
static void create_fdt(SiFiveUState *s, const MemMapEntry *memmap,
|
2023-01-11 20:09:41 +03:00
|
|
|
bool is_32_bit)
|
2018-03-02 15:31:14 +03:00
|
|
|
{
|
2023-01-11 20:09:41 +03:00
|
|
|
MachineState *ms = MACHINE(s);
|
|
|
|
uint64_t mem_size = ms->ram_size;
|
2018-03-02 15:31:14 +03:00
|
|
|
void *fdt;
|
2023-01-02 14:52:33 +03:00
|
|
|
int cpu, fdt_size;
|
2018-03-02 15:31:14 +03:00
|
|
|
uint32_t *cells;
|
|
|
|
char *nodename;
|
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;
|
2021-04-30 10:12:55 +03:00
|
|
|
static const char * const ethclk_names[2] = { "pclk", "hclk" };
|
2021-04-30 10:12:57 +03:00
|
|
|
static const char * const clint_compat[2] = {
|
|
|
|
"sifive,clint0", "riscv,clint0"
|
|
|
|
};
|
2021-04-30 10:12:58 +03:00
|
|
|
static const char * const plic_compat[2] = {
|
|
|
|
"sifive,plic-1.0.0", "riscv,plic0"
|
|
|
|
};
|
2018-03-02 15:31:14 +03:00
|
|
|
|
2020-11-02 17:44:36 +03:00
|
|
|
if (ms->dtb) {
|
2023-01-02 14:52:33 +03:00
|
|
|
fdt = ms->fdt = load_device_tree(ms->dtb, &fdt_size);
|
2020-10-22 08:32:24 +03:00
|
|
|
if (!fdt) {
|
|
|
|
error_report("load_device_tree() failed");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
} else {
|
2023-01-02 14:52:33 +03:00
|
|
|
fdt = ms->fdt = create_device_tree(&fdt_size);
|
2020-10-22 08:32:24 +03:00
|
|
|
if (!fdt) {
|
|
|
|
error_report("create_device_tree() failed");
|
|
|
|
exit(1);
|
|
|
|
}
|
2018-03-02 15:31:14 +03:00
|
|
|
}
|
|
|
|
|
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",
|
2020-09-11 20:34:47 +03:00
|
|
|
(long)memmap[SIFIVE_U_DEV_DRAM].base);
|
2018-03-02 15:31:14 +03:00
|
|
|
qemu_fdt_add_subnode(fdt, nodename);
|
|
|
|
qemu_fdt_setprop_cells(fdt, nodename, "reg",
|
2020-09-11 20:34:47 +03:00
|
|
|
memmap[SIFIVE_U_DEV_DRAM].base >> 32, memmap[SIFIVE_U_DEV_DRAM].base,
|
2018-03-02 15:31:14 +03:00
|
|
|
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",
|
2021-07-06 13:26:16 +03:00
|
|
|
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-12-16 21:22:45 +03:00
|
|
|
if (is_32_bit) {
|
|
|
|
qemu_fdt_setprop_string(fdt, nodename, "mmu-type", "riscv,sv32");
|
|
|
|
} else {
|
|
|
|
qemu_fdt_setprop_string(fdt, nodename, "mmu-type", "riscv,sv48");
|
|
|
|
}
|
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",
|
2020-09-11 20:34:47 +03:00
|
|
|
(long)memmap[SIFIVE_U_DEV_CLINT].base);
|
2018-03-02 15:31:14 +03:00
|
|
|
qemu_fdt_add_subnode(fdt, nodename);
|
2021-04-30 10:12:57 +03:00
|
|
|
qemu_fdt_setprop_string_array(fdt, nodename, "compatible",
|
|
|
|
(char **)&clint_compat, ARRAY_SIZE(clint_compat));
|
2018-03-02 15:31:14 +03:00
|
|
|
qemu_fdt_setprop_cells(fdt, nodename, "reg",
|
2020-09-11 20:34:47 +03:00
|
|
|
0x0, memmap[SIFIVE_U_DEV_CLINT].base,
|
|
|
|
0x0, memmap[SIFIVE_U_DEV_CLINT].size);
|
2018-03-02 15:31:14 +03:00
|
|
|
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",
|
2020-09-11 20:34:47 +03:00
|
|
|
(long)memmap[SIFIVE_U_DEV_OTP].base);
|
2020-06-08 17:17:33 +03:00
|
|
|
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",
|
2020-09-11 20:34:47 +03:00
|
|
|
0x0, memmap[SIFIVE_U_DEV_OTP].base,
|
|
|
|
0x0, memmap[SIFIVE_U_DEV_OTP].size);
|
2020-06-08 17:17:33 +03:00
|
|
|
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",
|
2020-09-11 20:34:47 +03:00
|
|
|
(long)memmap[SIFIVE_U_DEV_PRCI].base);
|
2019-09-06 19:20:10 +03:00
|
|
|
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",
|
2020-09-11 20:34:47 +03:00
|
|
|
0x0, memmap[SIFIVE_U_DEV_PRCI].base,
|
|
|
|
0x0, memmap[SIFIVE_U_DEV_PRCI].size);
|
2019-09-06 19:20:10 +03:00
|
|
|
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",
|
2020-09-11 20:34:47 +03:00
|
|
|
(long)memmap[SIFIVE_U_DEV_PLIC].base);
|
2018-03-02 15:31:14 +03:00
|
|
|
qemu_fdt_add_subnode(fdt, nodename);
|
|
|
|
qemu_fdt_setprop_cell(fdt, nodename, "#interrupt-cells", 1);
|
2021-04-30 10:12:58 +03:00
|
|
|
qemu_fdt_setprop_string_array(fdt, nodename, "compatible",
|
|
|
|
(char **)&plic_compat, ARRAY_SIZE(plic_compat));
|
2018-03-02 15:31:14 +03:00
|
|
|
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",
|
2020-09-11 20:34:47 +03:00
|
|
|
0x0, memmap[SIFIVE_U_DEV_PLIC].base,
|
|
|
|
0x0, memmap[SIFIVE_U_DEV_PLIC].size);
|
2022-12-11 06:08:25 +03:00
|
|
|
qemu_fdt_setprop_cell(fdt, nodename, "riscv,ndev",
|
|
|
|
SIFIVE_U_PLIC_NUM_SOURCES - 1);
|
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",
|
2020-09-11 20:34:47 +03:00
|
|
|
(long)memmap[SIFIVE_U_DEV_GPIO].base);
|
2020-06-08 17:17:36 +03:00
|
|
|
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",
|
2020-09-11 20:34:47 +03:00
|
|
|
0x0, memmap[SIFIVE_U_DEV_GPIO].base,
|
|
|
|
0x0, memmap[SIFIVE_U_DEV_GPIO].size);
|
2020-06-08 17:17:36 +03:00
|
|
|
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);
|
|
|
|
|
2020-09-01 04:39:11 +03:00
|
|
|
nodename = g_strdup_printf("/soc/dma@%lx",
|
2020-09-11 20:34:47 +03:00
|
|
|
(long)memmap[SIFIVE_U_DEV_PDMA].base);
|
2020-09-01 04:39:11 +03:00
|
|
|
qemu_fdt_add_subnode(fdt, nodename);
|
|
|
|
qemu_fdt_setprop_cell(fdt, nodename, "#dma-cells", 1);
|
|
|
|
qemu_fdt_setprop_cells(fdt, nodename, "interrupts",
|
|
|
|
SIFIVE_U_PDMA_IRQ0, SIFIVE_U_PDMA_IRQ1, SIFIVE_U_PDMA_IRQ2,
|
|
|
|
SIFIVE_U_PDMA_IRQ3, SIFIVE_U_PDMA_IRQ4, SIFIVE_U_PDMA_IRQ5,
|
|
|
|
SIFIVE_U_PDMA_IRQ6, SIFIVE_U_PDMA_IRQ7);
|
|
|
|
qemu_fdt_setprop_cell(fdt, nodename, "interrupt-parent", plic_phandle);
|
|
|
|
qemu_fdt_setprop_cells(fdt, nodename, "reg",
|
2020-09-11 20:34:47 +03:00
|
|
|
0x0, memmap[SIFIVE_U_DEV_PDMA].base,
|
|
|
|
0x0, memmap[SIFIVE_U_DEV_PDMA].size);
|
2020-09-01 04:39:11 +03:00
|
|
|
qemu_fdt_setprop_string(fdt, nodename, "compatible",
|
|
|
|
"sifive,fu540-c000-pdma");
|
|
|
|
g_free(nodename);
|
|
|
|
|
2020-07-20 09:49:08 +03:00
|
|
|
nodename = g_strdup_printf("/soc/cache-controller@%lx",
|
2020-09-11 20:34:47 +03:00
|
|
|
(long)memmap[SIFIVE_U_DEV_L2CC].base);
|
2020-07-20 09:49:08 +03:00
|
|
|
qemu_fdt_add_subnode(fdt, nodename);
|
|
|
|
qemu_fdt_setprop_cells(fdt, nodename, "reg",
|
2020-09-11 20:34:47 +03:00
|
|
|
0x0, memmap[SIFIVE_U_DEV_L2CC].base,
|
|
|
|
0x0, memmap[SIFIVE_U_DEV_L2CC].size);
|
2020-07-20 09:49:08 +03:00
|
|
|
qemu_fdt_setprop_cells(fdt, nodename, "interrupts",
|
|
|
|
SIFIVE_U_L2CC_IRQ0, SIFIVE_U_L2CC_IRQ1, SIFIVE_U_L2CC_IRQ2);
|
|
|
|
qemu_fdt_setprop_cell(fdt, nodename, "interrupt-parent", plic_phandle);
|
|
|
|
qemu_fdt_setprop(fdt, nodename, "cache-unified", NULL, 0);
|
|
|
|
qemu_fdt_setprop_cell(fdt, nodename, "cache-size", 2097152);
|
|
|
|
qemu_fdt_setprop_cell(fdt, nodename, "cache-sets", 1024);
|
|
|
|
qemu_fdt_setprop_cell(fdt, nodename, "cache-level", 2);
|
|
|
|
qemu_fdt_setprop_cell(fdt, nodename, "cache-block-size", 64);
|
|
|
|
qemu_fdt_setprop_string(fdt, nodename, "compatible",
|
|
|
|
"sifive,fu540-c000-ccache");
|
|
|
|
g_free(nodename);
|
|
|
|
|
2021-01-26 09:00:03 +03:00
|
|
|
nodename = g_strdup_printf("/soc/spi@%lx",
|
|
|
|
(long)memmap[SIFIVE_U_DEV_QSPI2].base);
|
|
|
|
qemu_fdt_add_subnode(fdt, nodename);
|
|
|
|
qemu_fdt_setprop_cell(fdt, nodename, "#size-cells", 0);
|
|
|
|
qemu_fdt_setprop_cell(fdt, nodename, "#address-cells", 1);
|
|
|
|
qemu_fdt_setprop_cells(fdt, nodename, "clocks",
|
|
|
|
prci_phandle, PRCI_CLK_TLCLK);
|
|
|
|
qemu_fdt_setprop_cell(fdt, nodename, "interrupts", SIFIVE_U_QSPI2_IRQ);
|
|
|
|
qemu_fdt_setprop_cell(fdt, nodename, "interrupt-parent", plic_phandle);
|
|
|
|
qemu_fdt_setprop_cells(fdt, nodename, "reg",
|
|
|
|
0x0, memmap[SIFIVE_U_DEV_QSPI2].base,
|
|
|
|
0x0, memmap[SIFIVE_U_DEV_QSPI2].size);
|
|
|
|
qemu_fdt_setprop_string(fdt, nodename, "compatible", "sifive,spi0");
|
|
|
|
g_free(nodename);
|
|
|
|
|
|
|
|
nodename = g_strdup_printf("/soc/spi@%lx/mmc@0",
|
|
|
|
(long)memmap[SIFIVE_U_DEV_QSPI2].base);
|
|
|
|
qemu_fdt_add_subnode(fdt, nodename);
|
|
|
|
qemu_fdt_setprop(fdt, nodename, "disable-wp", NULL, 0);
|
|
|
|
qemu_fdt_setprop_cells(fdt, nodename, "voltage-ranges", 3300, 3300);
|
|
|
|
qemu_fdt_setprop_cell(fdt, nodename, "spi-max-frequency", 20000000);
|
|
|
|
qemu_fdt_setprop_cell(fdt, nodename, "reg", 0);
|
|
|
|
qemu_fdt_setprop_string(fdt, nodename, "compatible", "mmc-spi-slot");
|
|
|
|
g_free(nodename);
|
|
|
|
|
2021-01-26 09:00:02 +03:00
|
|
|
nodename = g_strdup_printf("/soc/spi@%lx",
|
|
|
|
(long)memmap[SIFIVE_U_DEV_QSPI0].base);
|
|
|
|
qemu_fdt_add_subnode(fdt, nodename);
|
|
|
|
qemu_fdt_setprop_cell(fdt, nodename, "#size-cells", 0);
|
|
|
|
qemu_fdt_setprop_cell(fdt, nodename, "#address-cells", 1);
|
|
|
|
qemu_fdt_setprop_cells(fdt, nodename, "clocks",
|
|
|
|
prci_phandle, PRCI_CLK_TLCLK);
|
|
|
|
qemu_fdt_setprop_cell(fdt, nodename, "interrupts", SIFIVE_U_QSPI0_IRQ);
|
|
|
|
qemu_fdt_setprop_cell(fdt, nodename, "interrupt-parent", plic_phandle);
|
|
|
|
qemu_fdt_setprop_cells(fdt, nodename, "reg",
|
|
|
|
0x0, memmap[SIFIVE_U_DEV_QSPI0].base,
|
|
|
|
0x0, memmap[SIFIVE_U_DEV_QSPI0].size);
|
|
|
|
qemu_fdt_setprop_string(fdt, nodename, "compatible", "sifive,spi0");
|
|
|
|
g_free(nodename);
|
|
|
|
|
|
|
|
nodename = g_strdup_printf("/soc/spi@%lx/flash@0",
|
|
|
|
(long)memmap[SIFIVE_U_DEV_QSPI0].base);
|
|
|
|
qemu_fdt_add_subnode(fdt, nodename);
|
|
|
|
qemu_fdt_setprop_cell(fdt, nodename, "spi-rx-bus-width", 4);
|
|
|
|
qemu_fdt_setprop_cell(fdt, nodename, "spi-tx-bus-width", 4);
|
|
|
|
qemu_fdt_setprop(fdt, nodename, "m25p,fast-read", NULL, 0);
|
|
|
|
qemu_fdt_setprop_cell(fdt, nodename, "spi-max-frequency", 50000000);
|
|
|
|
qemu_fdt_setprop_cell(fdt, nodename, "reg", 0);
|
|
|
|
qemu_fdt_setprop_string(fdt, nodename, "compatible", "jedec,spi-nor");
|
|
|
|
g_free(nodename);
|
|
|
|
|
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",
|
2020-09-11 20:34:47 +03:00
|
|
|
(long)memmap[SIFIVE_U_DEV_GEM].base);
|
2018-04-26 23:59:08 +03:00
|
|
|
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",
|
2020-09-11 20:34:47 +03:00
|
|
|
0x0, memmap[SIFIVE_U_DEV_GEM].base,
|
|
|
|
0x0, memmap[SIFIVE_U_DEV_GEM].size,
|
|
|
|
0x0, memmap[SIFIVE_U_DEV_GEM_MGMT].base,
|
|
|
|
0x0, memmap[SIFIVE_U_DEV_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);
|
2021-04-30 10:12:55 +03:00
|
|
|
qemu_fdt_setprop_string_array(fdt, nodename, "clock-names",
|
|
|
|
(char **)ðclk_names, ARRAY_SIZE(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",
|
2020-09-11 20:34:47 +03:00
|
|
|
(long)memmap[SIFIVE_U_DEV_GEM].base);
|
2018-04-26 23:59:08 +03:00
|
|
|
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);
|
|
|
|
|
2021-09-09 06:55:15 +03:00
|
|
|
nodename = g_strdup_printf("/soc/pwm@%lx",
|
|
|
|
(long)memmap[SIFIVE_U_DEV_PWM0].base);
|
|
|
|
qemu_fdt_add_subnode(fdt, nodename);
|
|
|
|
qemu_fdt_setprop_string(fdt, nodename, "compatible", "sifive,pwm0");
|
|
|
|
qemu_fdt_setprop_cells(fdt, nodename, "reg",
|
|
|
|
0x0, memmap[SIFIVE_U_DEV_PWM0].base,
|
|
|
|
0x0, memmap[SIFIVE_U_DEV_PWM0].size);
|
|
|
|
qemu_fdt_setprop_cell(fdt, nodename, "interrupt-parent", plic_phandle);
|
|
|
|
qemu_fdt_setprop_cells(fdt, nodename, "interrupts",
|
|
|
|
SIFIVE_U_PWM0_IRQ0, SIFIVE_U_PWM0_IRQ1,
|
|
|
|
SIFIVE_U_PWM0_IRQ2, SIFIVE_U_PWM0_IRQ3);
|
|
|
|
qemu_fdt_setprop_cells(fdt, nodename, "clocks",
|
|
|
|
prci_phandle, PRCI_CLK_TLCLK);
|
|
|
|
qemu_fdt_setprop_cell(fdt, nodename, "#pwm-cells", 0);
|
|
|
|
g_free(nodename);
|
|
|
|
|
|
|
|
nodename = g_strdup_printf("/soc/pwm@%lx",
|
|
|
|
(long)memmap[SIFIVE_U_DEV_PWM1].base);
|
|
|
|
qemu_fdt_add_subnode(fdt, nodename);
|
|
|
|
qemu_fdt_setprop_string(fdt, nodename, "compatible", "sifive,pwm0");
|
|
|
|
qemu_fdt_setprop_cells(fdt, nodename, "reg",
|
|
|
|
0x0, memmap[SIFIVE_U_DEV_PWM1].base,
|
|
|
|
0x0, memmap[SIFIVE_U_DEV_PWM1].size);
|
|
|
|
qemu_fdt_setprop_cell(fdt, nodename, "interrupt-parent", plic_phandle);
|
|
|
|
qemu_fdt_setprop_cells(fdt, nodename, "interrupts",
|
|
|
|
SIFIVE_U_PWM1_IRQ0, SIFIVE_U_PWM1_IRQ1,
|
|
|
|
SIFIVE_U_PWM1_IRQ2, SIFIVE_U_PWM1_IRQ3);
|
|
|
|
qemu_fdt_setprop_cells(fdt, nodename, "clocks",
|
|
|
|
prci_phandle, PRCI_CLK_TLCLK);
|
|
|
|
qemu_fdt_setprop_cell(fdt, nodename, "#pwm-cells", 0);
|
|
|
|
g_free(nodename);
|
|
|
|
|
2020-11-11 12:47:25 +03:00
|
|
|
nodename = g_strdup_printf("/soc/serial@%lx",
|
|
|
|
(long)memmap[SIFIVE_U_DEV_UART1].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_DEV_UART1].base,
|
|
|
|
0x0, memmap[SIFIVE_U_DEV_UART1].size);
|
|
|
|
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_UART1_IRQ);
|
|
|
|
|
|
|
|
qemu_fdt_setprop_string(fdt, "/aliases", "serial1", nodename);
|
|
|
|
g_free(nodename);
|
|
|
|
|
2019-09-06 19:20:13 +03:00
|
|
|
nodename = g_strdup_printf("/soc/serial@%lx",
|
2020-09-11 20:34:47 +03:00
|
|
|
(long)memmap[SIFIVE_U_DEV_UART0].base);
|
2018-03-02 15:31:14 +03:00
|
|
|
qemu_fdt_add_subnode(fdt, nodename);
|
|
|
|
qemu_fdt_setprop_string(fdt, nodename, "compatible", "sifive,uart0");
|
|
|
|
qemu_fdt_setprop_cells(fdt, nodename, "reg",
|
2020-09-11 20:34:47 +03:00
|
|
|
0x0, memmap[SIFIVE_U_DEV_UART0].base,
|
|
|
|
0x0, memmap[SIFIVE_U_DEV_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);
|
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
|
|
|
{
|
2021-02-20 17:48:04 +03:00
|
|
|
const 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();
|
2019-10-09 02:32:11 +03:00
|
|
|
MemoryRegion *flash0 = g_new(MemoryRegion, 1);
|
2020-09-11 20:34:47 +03:00
|
|
|
target_ulong start_addr = memmap[SIFIVE_U_DEV_DRAM].base;
|
2020-10-14 03:17:33 +03:00
|
|
|
target_ulong firmware_end_addr, kernel_start_addr;
|
2022-12-29 12:18:26 +03:00
|
|
|
const char *firmware_name;
|
2020-07-01 21:39:49 +03:00
|
|
|
uint32_t start_addr_hi32 = 0x00000000;
|
2018-03-04 01:52:13 +03:00
|
|
|
int i;
|
2020-07-01 21:39:47 +03:00
|
|
|
uint32_t fdt_load_addr;
|
2020-07-01 21:39:48 +03:00
|
|
|
uint64_t kernel_entry;
|
2021-01-26 09:00:02 +03:00
|
|
|
DriveInfo *dinfo;
|
2021-11-17 19:33:57 +03:00
|
|
|
BlockBackend *blk;
|
|
|
|
DeviceState *flash_dev, *sd_dev, *card_dev;
|
2021-01-26 09:00:03 +03:00
|
|
|
qemu_irq flash_cs, sd_cs;
|
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);
|
qom: Put name parameter before value / visitor parameter
The object_property_set_FOO() setters take property name and value in
an unusual order:
void object_property_set_FOO(Object *obj, FOO_TYPE value,
const char *name, Error **errp)
Having to pass value before name feels grating. Swap them.
Same for object_property_set(), object_property_get(), and
object_property_parse().
Convert callers with this Coccinelle script:
@@
identifier fun = {
object_property_get, object_property_parse, object_property_set_str,
object_property_set_link, object_property_set_bool,
object_property_set_int, object_property_set_uint, object_property_set,
object_property_set_qobject
};
expression obj, v, name, errp;
@@
- fun(obj, v, name, errp)
+ fun(obj, name, v, errp)
Chokes on hw/arm/musicpal.c's lcd_refresh() with the unhelpful error
message "no position information". Convert that one manually.
Fails to convert hw/arm/armsse.c, because Coccinelle gets confused by
ARMSSE being used both as typedef and function-like macro there.
Convert manually.
Fails to convert hw/rx/rx-gdbsim.c, because Coccinelle gets confused
by RXCPU being used both as typedef and function-like macro there.
Convert manually. The other files using RXCPU that way don't need
conversion.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Message-Id: <20200707160613.848843-27-armbru@redhat.com>
[Straightforwad conflict with commit 2336172d9b "audio: set default
value for pcspk.iobase property" resolved]
2020-07-07 19:05:54 +03:00
|
|
|
object_property_set_uint(OBJECT(&s->soc), "serial", s->serial,
|
|
|
|
&error_abort);
|
2020-10-14 03:17:25 +03:00
|
|
|
object_property_set_str(OBJECT(&s->soc), "cpu-type", machine->cpu_type,
|
|
|
|
&error_abort);
|
2022-01-06 00:39:36 +03:00
|
|
|
qdev_realize(DEVICE(&s->soc), NULL, &error_fatal);
|
2018-03-02 15:31:14 +03:00
|
|
|
|
|
|
|
/* register RAM */
|
2020-09-11 20:34:47 +03:00
|
|
|
memory_region_add_subregion(system_memory, memmap[SIFIVE_U_DEV_DRAM].base,
|
2021-10-20 04:41:11 +03:00
|
|
|
machine->ram);
|
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",
|
2020-09-11 20:34:47 +03:00
|
|
|
memmap[SIFIVE_U_DEV_FLASH0].size, &error_fatal);
|
|
|
|
memory_region_add_subregion(system_memory, memmap[SIFIVE_U_DEV_FLASH0].base,
|
2019-10-09 02:32:11 +03:00
|
|
|
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 */
|
2023-01-11 20:09:41 +03:00
|
|
|
create_fdt(s, memmap, riscv_is_32bit(&s->soc.u_cpus));
|
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:
|
2020-09-11 20:34:47 +03:00
|
|
|
start_addr = memmap[SIFIVE_U_DEV_FLASH0].base;
|
2020-06-16 03:50:39 +03:00
|
|
|
break;
|
|
|
|
case MSEL_L2LIM_QSPI0_FLASH:
|
|
|
|
case MSEL_L2LIM_QSPI2_SD:
|
2020-09-11 20:34:47 +03:00
|
|
|
start_addr = memmap[SIFIVE_U_DEV_L2LIM].base;
|
2020-06-16 03:50:39 +03:00
|
|
|
break;
|
|
|
|
default:
|
2020-09-11 20:34:47 +03:00
|
|
|
start_addr = memmap[SIFIVE_U_DEV_DRAM].base;
|
2020-06-16 03:50:39 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2022-12-29 12:18:26 +03:00
|
|
|
firmware_name = riscv_default_firmware_name(&s->soc.u_cpus);
|
|
|
|
firmware_end_addr = riscv_find_and_load_firmware(machine, firmware_name,
|
|
|
|
start_addr, NULL);
|
2019-06-25 01:11:52 +03:00
|
|
|
|
2018-03-02 15:31:14 +03:00
|
|
|
if (machine->kernel_filename) {
|
2021-01-16 02:00:27 +03:00
|
|
|
kernel_start_addr = riscv_calc_kernel_start_addr(&s->soc.u_cpus,
|
2020-10-14 03:17:33 +03:00
|
|
|
firmware_end_addr);
|
|
|
|
|
2023-02-06 17:00:20 +03:00
|
|
|
kernel_entry = riscv_load_kernel(machine, &s->soc.u_cpus,
|
2023-02-06 17:00:21 +03:00
|
|
|
kernel_start_addr, true, NULL);
|
2020-07-01 21:39:48 +03:00
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* If dynamic firmware is used, it doesn't know where is the next mode
|
|
|
|
* if kernel argument is not set.
|
|
|
|
*/
|
|
|
|
kernel_entry = 0;
|
2018-03-02 15:31:14 +03:00
|
|
|
}
|
|
|
|
|
2023-02-01 20:12:11 +03:00
|
|
|
fdt_load_addr = riscv_compute_fdt_addr(memmap[SIFIVE_U_DEV_DRAM].base,
|
hw/riscv: change riscv_compute_fdt_addr() semantics
As it is now, riscv_compute_fdt_addr() is receiving a dram_base, a
mem_size (which is defaulted to MachineState::ram_size in all boards)
and the FDT pointer. And it makes a very important assumption: the DRAM
interval dram_base + mem_size is contiguous. This is indeed the case for
most boards that use a FDT.
The Icicle Kit board works with 2 distinct RAM banks that are separated
by a gap. We have a lower bank with 1GiB size, a gap follows, then at
64GiB the high memory starts. MachineClass::default_ram_size for this
board is set to 1.5Gb, and machine_init() is enforcing it as minimal RAM
size, meaning that there we'll always have at least 512 MiB in the Hi
RAM area.
Using riscv_compute_fdt_addr() in this board is weird because not only
the board has sparse RAM, and it's calling it using the base address of
the Lo RAM area, but it's also using a mem_size that we have guarantees
that it will go up to the Hi RAM. All the function assumptions doesn't
work for this board.
In fact, what makes the function works at all in this case is a
coincidence. Commit 1a475d39ef54 introduced a 3GB boundary for the FDT,
down from 4Gb, that is enforced if dram_base is lower than 3072 MiB. For
the Icicle Kit board, memmap[MICROCHIP_PFSOC_DRAM_LO].base is 0x80000000
(2 Gb) and it has a 1Gb size, so it will fall in the conditions to put
the FDT under a 3Gb address, which happens to be exactly at the end of
DRAM_LO. If the base address of the Lo area started later than 3Gb this
function would be unusable by the board. Changing any assumptions inside
riscv_compute_fdt_addr() can also break it by accident as well.
Let's change riscv_compute_fdt_addr() semantics to be appropriate to the
Icicle Kit board and for future boards that might have sparse RAM
topologies to worry about:
- relieve the condition that the dram_base + mem_size area is contiguous,
since this is already not the case today;
- receive an extra 'dram_size' size attribute that refers to a contiguous
RAM block that the board wants the FDT to reside on.
Together with 'mem_size' and 'fdt', which are now now being consumed by a
MachineState pointer, we're able to make clear assumptions based on the
DRAM block and total mem_size available to ensure that the FDT will be put
in a valid RAM address.
Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Message-Id: <20230201171212.1219375-4-dbarboza@ventanamicro.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
2023-02-01 20:12:12 +03:00
|
|
|
memmap[SIFIVE_U_DEV_DRAM].size,
|
|
|
|
machine);
|
2023-02-01 20:12:11 +03:00
|
|
|
riscv_load_fdt(fdt_load_addr, machine->fdt);
|
|
|
|
|
2021-01-16 02:00:27 +03:00
|
|
|
if (!riscv_is_32bit(&s->soc.u_cpus)) {
|
2020-12-16 21:22:45 +03:00
|
|
|
start_addr_hi32 = (uint64_t)start_addr >> 32;
|
|
|
|
}
|
2020-07-01 21:39:47 +03:00
|
|
|
|
2018-03-02 15:31:14 +03:00
|
|
|
/* reset vector */
|
2021-07-08 17:33:19 +03:00
|
|
|
uint32_t reset_vec[12] = {
|
2020-06-16 03:50:39 +03:00
|
|
|
s->msel, /* MSEL pin state */
|
2020-07-01 21:39:48 +03:00
|
|
|
0x00000297, /* 1: auipc t0, %pcrel_hi(fw_dyn) */
|
2021-07-08 17:33:19 +03:00
|
|
|
0x02c28613, /* addi a2, t0, %pcrel_lo(1b) */
|
2018-03-02 15:31:14 +03:00
|
|
|
0xf1402573, /* csrr a0, mhartid */
|
2020-12-16 21:22:45 +03:00
|
|
|
0,
|
|
|
|
0,
|
2018-03-02 15:31:14 +03:00
|
|
|
0x00028067, /* jr t0 */
|
2019-10-09 02:32:18 +03:00
|
|
|
start_addr, /* start: .dword */
|
2020-07-01 21:39:49 +03:00
|
|
|
start_addr_hi32,
|
2020-07-01 21:39:47 +03:00
|
|
|
fdt_load_addr, /* fdt_laddr: .dword */
|
2021-07-08 17:33:19 +03:00
|
|
|
0x00000000,
|
2020-07-01 21:39:47 +03:00
|
|
|
0x00000000,
|
2020-07-01 21:39:48 +03:00
|
|
|
/* fw_dyn: */
|
2018-03-02 15:31:14 +03:00
|
|
|
};
|
2021-01-16 02:00:27 +03:00
|
|
|
if (riscv_is_32bit(&s->soc.u_cpus)) {
|
2020-12-16 21:22:45 +03:00
|
|
|
reset_vec[4] = 0x0202a583; /* lw a1, 32(t0) */
|
|
|
|
reset_vec[5] = 0x0182a283; /* lw t0, 24(t0) */
|
|
|
|
} else {
|
|
|
|
reset_vec[4] = 0x0202b583; /* ld a1, 32(t0) */
|
|
|
|
reset_vec[5] = 0x0182b283; /* ld t0, 24(t0) */
|
|
|
|
}
|
|
|
|
|
2018-03-02 15:31:14 +03:00
|
|
|
|
2018-03-04 01:52:13 +03:00
|
|
|
/* copy in the reset vector in little_endian byte order */
|
2020-07-01 21:39:47 +03:00
|
|
|
for (i = 0; i < ARRAY_SIZE(reset_vec); i++) {
|
2018-03-04 01:52:13 +03:00
|
|
|
reset_vec[i] = cpu_to_le32(reset_vec[i]);
|
|
|
|
}
|
|
|
|
rom_add_blob_fixed_as("mrom.reset", reset_vec, sizeof(reset_vec),
|
2020-09-11 20:34:47 +03:00
|
|
|
memmap[SIFIVE_U_DEV_MROM].base, &address_space_memory);
|
2020-07-01 21:39:48 +03:00
|
|
|
|
2020-12-16 21:22:37 +03:00
|
|
|
riscv_rom_copy_firmware_info(machine, memmap[SIFIVE_U_DEV_MROM].base,
|
2020-09-11 20:34:47 +03:00
|
|
|
memmap[SIFIVE_U_DEV_MROM].size,
|
2020-07-01 21:39:48 +03:00
|
|
|
sizeof(reset_vec), kernel_entry);
|
2021-01-26 09:00:02 +03:00
|
|
|
|
|
|
|
/* Connect an SPI flash to SPI0 */
|
|
|
|
flash_dev = qdev_new("is25wp256");
|
2021-11-17 19:33:58 +03:00
|
|
|
dinfo = drive_get(IF_MTD, 0, 0);
|
2021-01-26 09:00:02 +03:00
|
|
|
if (dinfo) {
|
|
|
|
qdev_prop_set_drive_err(flash_dev, "drive",
|
|
|
|
blk_by_legacy_dinfo(dinfo),
|
|
|
|
&error_fatal);
|
|
|
|
}
|
|
|
|
qdev_realize_and_unref(flash_dev, BUS(s->soc.spi0.spi), &error_fatal);
|
|
|
|
|
|
|
|
flash_cs = qdev_get_gpio_in_named(flash_dev, SSI_GPIO_CS, 0);
|
|
|
|
sysbus_connect_irq(SYS_BUS_DEVICE(&s->soc.spi0), 1, flash_cs);
|
2021-01-26 09:00:03 +03:00
|
|
|
|
|
|
|
/* Connect an SD card to SPI2 */
|
|
|
|
sd_dev = ssi_create_peripheral(s->soc.spi2.spi, "ssi-sd");
|
|
|
|
|
|
|
|
sd_cs = qdev_get_gpio_in_named(sd_dev, SSI_GPIO_CS, 0);
|
|
|
|
sysbus_connect_irq(SYS_BUS_DEVICE(&s->soc.spi2), 1, sd_cs);
|
2021-11-17 19:33:57 +03:00
|
|
|
|
|
|
|
dinfo = drive_get(IF_SD, 0, 0);
|
|
|
|
blk = dinfo ? blk_by_legacy_dinfo(dinfo) : NULL;
|
|
|
|
card_dev = qdev_new(TYPE_SD_CARD);
|
|
|
|
qdev_prop_set_drive_err(card_dev, "drive", blk, &error_fatal);
|
|
|
|
qdev_prop_set_bit(card_dev, "spi", true);
|
|
|
|
qdev_realize_and_unref(card_dev,
|
|
|
|
qdev_get_child_bus(sd_dev, "sd-bus"),
|
|
|
|
&error_fatal);
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void sifive_u_machine_instance_init(Object *obj)
|
|
|
|
{
|
|
|
|
SiFiveUState *s = RISCV_U_MACHINE(obj);
|
|
|
|
|
|
|
|
s->start_in_flash = false;
|
2020-06-08 17:17:40 +03:00
|
|
|
s->msel = 0;
|
2022-03-02 01:52:20 +03:00
|
|
|
object_property_add_uint32_ptr(obj, "msel", &s->msel,
|
|
|
|
OBJ_PROP_FLAG_READWRITE);
|
2020-06-08 17:17:40 +03:00
|
|
|
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;
|
2022-03-02 01:52:20 +03:00
|
|
|
object_property_add_uint32_ptr(obj, "serial", &s->serial,
|
|
|
|
OBJ_PROP_FLAG_READWRITE);
|
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;
|
2021-01-09 17:36:37 +03:00
|
|
|
mc->default_cpu_type = SIFIVE_U_CPU;
|
2020-03-03 01:57:22 +03:00
|
|
|
mc->default_cpus = mc->min_cpus;
|
2021-10-20 04:41:11 +03:00
|
|
|
mc->default_ram_id = "riscv.sifive.u.ram";
|
2020-09-22 01:10:45 +03:00
|
|
|
|
|
|
|
object_class_property_add_bool(oc, "start-in-flash",
|
|
|
|
sifive_u_machine_get_start_in_flash,
|
|
|
|
sifive_u_machine_set_start_in_flash);
|
|
|
|
object_class_property_set_description(oc, "start-in-flash",
|
|
|
|
"Set on to tell QEMU's ROM to jump to "
|
|
|
|
"flash. Otherwise QEMU will jump to DRAM "
|
|
|
|
"or L2LIM depending on the msel value");
|
2020-03-03 01:57:22 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
{
|
|
|
|
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);
|
2020-09-01 04:38:58 +03:00
|
|
|
qdev_prop_set_uint64(DEVICE(&s->e_cpus), "resetvec", 0x1004);
|
2019-09-06 19:20:06 +03:00
|
|
|
|
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);
|
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);
|
2020-09-01 04:39:11 +03:00
|
|
|
object_initialize_child(obj, "pdma", &s->dma, TYPE_SIFIVE_PDMA);
|
2021-01-26 09:00:02 +03:00
|
|
|
object_initialize_child(obj, "spi0", &s->spi0, TYPE_SIFIVE_SPI);
|
2021-01-26 09:00:03 +03:00
|
|
|
object_initialize_child(obj, "spi2", &s->spi2, TYPE_SIFIVE_SPI);
|
2021-09-09 06:55:15 +03:00
|
|
|
object_initialize_child(obj, "pwm0", &s->pwm[0], TYPE_SIFIVE_PWM);
|
|
|
|
object_initialize_child(obj, "pwm1", &s->pwm[1], TYPE_SIFIVE_PWM);
|
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);
|
2021-02-20 17:48:04 +03:00
|
|
|
const MemMapEntry *memmap = sifive_u_memmap;
|
2018-04-26 21:15:24 +03:00
|
|
|
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;
|
2021-09-09 06:55:15 +03:00
|
|
|
int i, j;
|
2018-04-26 23:59:08 +03:00
|
|
|
NICInfo *nd = &nd_table[0];
|
2018-04-26 21:15:24 +03:00
|
|
|
|
2020-10-14 03:17:25 +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", s->cpu_type);
|
|
|
|
qdev_prop_set_uint64(DEVICE(&s->u_cpus), "resetvec", 0x1004);
|
|
|
|
|
2022-05-14 09:29:41 +03:00
|
|
|
sysbus_realize(SYS_BUS_DEVICE(&s->e_cpus), &error_fatal);
|
|
|
|
sysbus_realize(SYS_BUS_DEVICE(&s->u_cpus), &error_fatal);
|
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",
|
2020-09-11 20:34:47 +03:00
|
|
|
memmap[SIFIVE_U_DEV_MROM].size, &error_fatal);
|
|
|
|
memory_region_add_subregion(system_memory, memmap[SIFIVE_U_DEV_MROM].base,
|
2018-04-26 21:15:24 +03:00
|
|
|
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",
|
2020-09-11 20:34:47 +03:00
|
|
|
memmap[SIFIVE_U_DEV_L2LIM].size, &error_fatal);
|
|
|
|
memory_region_add_subregion(system_memory, memmap[SIFIVE_U_DEV_L2LIM].base,
|
2019-10-09 02:32:07 +03:00
|
|
|
l2lim_mem);
|
|
|
|
|
2019-05-17 18:51:25 +03:00
|
|
|
/* create PLIC hart topology configuration string */
|
2021-10-22 09:01:31 +03:00
|
|
|
plic_hart_config = riscv_plic_hart_config_string(ms->smp.cpus);
|
2019-05-17 18:51:25 +03:00
|
|
|
|
2018-03-02 15:31:14 +03:00
|
|
|
/* MMIO */
|
2020-09-11 20:34:47 +03:00
|
|
|
s->plic = sifive_plic_create(memmap[SIFIVE_U_DEV_PLIC].base,
|
2021-08-30 08:35:02 +03:00
|
|
|
plic_hart_config, ms->smp.cpus, 0,
|
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,
|
2020-09-11 20:34:47 +03:00
|
|
|
memmap[SIFIVE_U_DEV_PLIC].size);
|
2019-12-10 10:14:37 +03:00
|
|
|
g_free(plic_hart_config);
|
2020-09-11 20:34:47 +03:00
|
|
|
sifive_uart_create(system_memory, memmap[SIFIVE_U_DEV_UART0].base,
|
2018-04-26 23:54:12 +03:00
|
|
|
serial_hd(0), qdev_get_gpio_in(DEVICE(s->plic), SIFIVE_U_UART0_IRQ));
|
2020-09-11 20:34:47 +03:00
|
|
|
sifive_uart_create(system_memory, memmap[SIFIVE_U_DEV_UART1].base,
|
2018-12-14 03:19:03 +03:00
|
|
|
serial_hd(1), qdev_get_gpio_in(DEVICE(s->plic), SIFIVE_U_UART1_IRQ));
|
2021-08-31 14:06:01 +03:00
|
|
|
riscv_aclint_swi_create(memmap[SIFIVE_U_DEV_CLINT].base, 0,
|
|
|
|
ms->smp.cpus, false);
|
|
|
|
riscv_aclint_mtimer_create(memmap[SIFIVE_U_DEV_CLINT].base +
|
|
|
|
RISCV_ACLINT_SWI_SIZE,
|
|
|
|
RISCV_ACLINT_DEFAULT_MTIMER_SIZE, 0, ms->smp.cpus,
|
|
|
|
RISCV_ACLINT_DEFAULT_MTIMECMP, RISCV_ACLINT_DEFAULT_MTIME,
|
2021-07-06 13:26:16 +03:00
|
|
|
CLINT_TIMEBASE_FREQ, false);
|
2018-04-26 23:59:08 +03:00
|
|
|
|
2020-06-30 12:03:42 +03:00
|
|
|
if (!sysbus_realize(SYS_BUS_DEVICE(&s->prci), errp)) {
|
|
|
|
return;
|
|
|
|
}
|
2020-09-11 20:34:47 +03:00
|
|
|
sysbus_mmio_map(SYS_BUS_DEVICE(&s->prci), 0, memmap[SIFIVE_U_DEV_PRCI].base);
|
2019-09-06 19:20:10 +03:00
|
|
|
|
2020-06-08 17:17:36 +03:00
|
|
|
qdev_prop_set_uint32(DEVICE(&s->gpio), "ngpio", 16);
|
2020-06-30 12:03:42 +03:00
|
|
|
if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpio), errp)) {
|
|
|
|
return;
|
|
|
|
}
|
2020-09-11 20:34:47 +03:00
|
|
|
sysbus_mmio_map(SYS_BUS_DEVICE(&s->gpio), 0, memmap[SIFIVE_U_DEV_GPIO].base);
|
2020-06-08 17:17:36 +03:00
|
|
|
|
|
|
|
/* 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-09-01 04:39:11 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/* PDMA */
|
|
|
|
sysbus_realize(SYS_BUS_DEVICE(&s->dma), errp);
|
2020-09-11 20:34:47 +03:00
|
|
|
sysbus_mmio_map(SYS_BUS_DEVICE(&s->dma), 0, memmap[SIFIVE_U_DEV_PDMA].base);
|
2020-09-01 04:39:11 +03:00
|
|
|
|
|
|
|
/* Connect PDMA interrupts to the PLIC */
|
|
|
|
for (i = 0; i < SIFIVE_PDMA_IRQS; i++) {
|
|
|
|
sysbus_connect_irq(SYS_BUS_DEVICE(&s->dma), i,
|
|
|
|
qdev_get_gpio_in(DEVICE(s->plic),
|
|
|
|
SIFIVE_U_PDMA_IRQ0 + i));
|
2020-06-08 17:17:36 +03:00
|
|
|
}
|
|
|
|
|
2020-03-03 02:08:51 +03:00
|
|
|
qdev_prop_set_uint32(DEVICE(&s->otp), "serial", s->serial);
|
2020-06-30 12:03:42 +03:00
|
|
|
if (!sysbus_realize(SYS_BUS_DEVICE(&s->otp), errp)) {
|
|
|
|
return;
|
|
|
|
}
|
2020-09-11 20:34:47 +03:00
|
|
|
sysbus_mmio_map(SYS_BUS_DEVICE(&s->otp), 0, memmap[SIFIVE_U_DEV_OTP].base);
|
2019-09-06 19:20:16 +03:00
|
|
|
|
2020-07-15 17:04:40 +03:00
|
|
|
/* FIXME use qdev NIC properties instead of nd_table[] */
|
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);
|
|
|
|
}
|
qom: Put name parameter before value / visitor parameter
The object_property_set_FOO() setters take property name and value in
an unusual order:
void object_property_set_FOO(Object *obj, FOO_TYPE value,
const char *name, Error **errp)
Having to pass value before name feels grating. Swap them.
Same for object_property_set(), object_property_get(), and
object_property_parse().
Convert callers with this Coccinelle script:
@@
identifier fun = {
object_property_get, object_property_parse, object_property_set_str,
object_property_set_link, object_property_set_bool,
object_property_set_int, object_property_set_uint, object_property_set,
object_property_set_qobject
};
expression obj, v, name, errp;
@@
- fun(obj, v, name, errp)
+ fun(obj, name, v, errp)
Chokes on hw/arm/musicpal.c's lcd_refresh() with the unhelpful error
message "no position information". Convert that one manually.
Fails to convert hw/arm/armsse.c, because Coccinelle gets confused by
ARMSSE being used both as typedef and function-like macro there.
Convert manually.
Fails to convert hw/rx/rx-gdbsim.c, because Coccinelle gets confused
by RXCPU being used both as typedef and function-like macro there.
Convert manually. The other files using RXCPU that way don't need
conversion.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Message-Id: <20200707160613.848843-27-armbru@redhat.com>
[Straightforwad conflict with commit 2336172d9b "audio: set default
value for pcspk.iobase property" resolved]
2020-07-07 19:05:54 +03:00
|
|
|
object_property_set_int(OBJECT(&s->gem), "revision", GEM_REVISION,
|
2018-04-26 23:59:08 +03:00
|
|
|
&error_abort);
|
error: Eliminate error_propagate() with Coccinelle, part 1
When all we do with an Error we receive into a local variable is
propagating to somewhere else, we can just as well receive it there
right away. Convert
if (!foo(..., &err)) {
...
error_propagate(errp, err);
...
return ...
}
to
if (!foo(..., errp)) {
...
...
return ...
}
where nothing else needs @err. Coccinelle script:
@rule1 forall@
identifier fun, err, errp, lbl;
expression list args, args2;
binary operator op;
constant c1, c2;
symbol false;
@@
if (
(
- fun(args, &err, args2)
+ fun(args, errp, args2)
|
- !fun(args, &err, args2)
+ !fun(args, errp, args2)
|
- fun(args, &err, args2) op c1
+ fun(args, errp, args2) op c1
)
)
{
... when != err
when != lbl:
when strict
- error_propagate(errp, err);
... when != err
(
return;
|
return c2;
|
return false;
)
}
@rule2 forall@
identifier fun, err, errp, lbl;
expression list args, args2;
expression var;
binary operator op;
constant c1, c2;
symbol false;
@@
- var = fun(args, &err, args2);
+ var = fun(args, errp, args2);
... when != err
if (
(
var
|
!var
|
var op c1
)
)
{
... when != err
when != lbl:
when strict
- error_propagate(errp, err);
... when != err
(
return;
|
return c2;
|
return false;
|
return var;
)
}
@depends on rule1 || rule2@
identifier err;
@@
- Error *err = NULL;
... when != err
Not exactly elegant, I'm afraid.
The "when != lbl:" is necessary to avoid transforming
if (fun(args, &err)) {
goto out
}
...
out:
error_propagate(errp, err);
even though other paths to label out still need the error_propagate().
For an actual example, see sclp_realize().
Without the "when strict", Coccinelle transforms vfio_msix_setup(),
incorrectly. I don't know what exactly "when strict" does, only that
it helps here.
The match of return is narrower than what I want, but I can't figure
out how to express "return where the operand doesn't use @err". For
an example where it's too narrow, see vfio_intx_enable().
Silently fails to convert hw/arm/armsse.c, because Coccinelle gets
confused by ARMSSE being used both as typedef and function-like macro
there. Converted manually.
Line breaks tidied up manually. One nested declaration of @local_err
deleted manually. Preexisting unwanted blank line dropped in
hw/riscv/sifive_e.c.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Message-Id: <20200707160613.848843-35-armbru@redhat.com>
2020-07-07 19:06:02 +03:00
|
|
|
if (!sysbus_realize(SYS_BUS_DEVICE(&s->gem), errp)) {
|
2018-04-26 23:59:08 +03:00
|
|
|
return;
|
|
|
|
}
|
2020-09-11 20:34:47 +03:00
|
|
|
sysbus_mmio_map(SYS_BUS_DEVICE(&s->gem), 0, memmap[SIFIVE_U_DEV_GEM].base);
|
2018-04-26 23:59:08 +03:00
|
|
|
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
|
|
|
|
2021-09-09 06:55:15 +03:00
|
|
|
/* PWM */
|
|
|
|
for (i = 0; i < 2; i++) {
|
|
|
|
if (!sysbus_realize(SYS_BUS_DEVICE(&s->pwm[i]), errp)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
sysbus_mmio_map(SYS_BUS_DEVICE(&s->pwm[i]), 0,
|
|
|
|
memmap[SIFIVE_U_DEV_PWM0].base + (0x1000 * i));
|
|
|
|
|
|
|
|
/* Connect PWM interrupts to the PLIC */
|
|
|
|
for (j = 0; j < SIFIVE_PWM_IRQS; j++) {
|
|
|
|
sysbus_connect_irq(SYS_BUS_DEVICE(&s->pwm[i]), j,
|
|
|
|
qdev_get_gpio_in(DEVICE(s->plic),
|
|
|
|
SIFIVE_U_PWM0_IRQ0 + (i * 4) + j));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-06 19:20:17 +03:00
|
|
|
create_unimplemented_device("riscv.sifive.u.gem-mgmt",
|
2020-09-11 20:34:47 +03:00
|
|
|
memmap[SIFIVE_U_DEV_GEM_MGMT].base, memmap[SIFIVE_U_DEV_GEM_MGMT].size);
|
2020-06-16 03:50:41 +03:00
|
|
|
|
|
|
|
create_unimplemented_device("riscv.sifive.u.dmc",
|
2020-09-11 20:34:47 +03:00
|
|
|
memmap[SIFIVE_U_DEV_DMC].base, memmap[SIFIVE_U_DEV_DMC].size);
|
2020-07-20 09:49:08 +03:00
|
|
|
|
|
|
|
create_unimplemented_device("riscv.sifive.u.l2cc",
|
2020-09-11 20:34:47 +03:00
|
|
|
memmap[SIFIVE_U_DEV_L2CC].base, memmap[SIFIVE_U_DEV_L2CC].size);
|
2021-01-26 09:00:02 +03:00
|
|
|
|
|
|
|
sysbus_realize(SYS_BUS_DEVICE(&s->spi0), errp);
|
|
|
|
sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi0), 0,
|
|
|
|
memmap[SIFIVE_U_DEV_QSPI0].base);
|
|
|
|
sysbus_connect_irq(SYS_BUS_DEVICE(&s->spi0), 0,
|
|
|
|
qdev_get_gpio_in(DEVICE(s->plic), SIFIVE_U_QSPI0_IRQ));
|
2021-01-26 09:00:03 +03:00
|
|
|
sysbus_realize(SYS_BUS_DEVICE(&s->spi2), errp);
|
|
|
|
sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi2), 0,
|
|
|
|
memmap[SIFIVE_U_DEV_QSPI2].base);
|
|
|
|
sysbus_connect_irq(SYS_BUS_DEVICE(&s->spi2), 0,
|
|
|
|
qdev_get_gpio_in(DEVICE(s->plic), SIFIVE_U_QSPI2_IRQ));
|
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),
|
2020-10-14 03:17:25 +03:00
|
|
|
DEFINE_PROP_STRING("cpu-type", SiFiveUSoCState, cpu_type),
|
2020-03-03 02:08:51 +03:00
|
|
|
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)
|