sifive_u.c 29.9 KB
Newer Older
1 2 3 4 5
/*
 * 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.
6
 * Copyright (c) 2019 Bin Meng <bmeng.cn@gmail.com>
7 8 9 10 11 12
 *
 * Provides a board compatible with the SiFive Freedom U SDK:
 *
 * 0) UART
 * 1) CLINT (Core Level Interruptor)
 * 2) PLIC (Platform Level Interrupt Controller)
13
 * 3) PRCI (Power, Reset, Clock, Interrupt)
14 15 16
 * 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
17
 *
18
 * This board currently generates devicetree dynamically that indicates at least
19
 * two harts and up to five harts.
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
 *
 * 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"
38
#include "qapi/visitor.h"
39
#include "hw/boards.h"
40
#include "hw/irq.h"
41 42 43
#include "hw/loader.h"
#include "hw/sysbus.h"
#include "hw/char/serial.h"
44
#include "hw/cpu/cluster.h"
45
#include "hw/misc/unimp.h"
46 47 48 49 50 51
#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"
52
#include "hw/riscv/boot.h"
53
#include "chardev/char.h"
54
#include "net/eth.h"
55 56
#include "sysemu/arch_init.h"
#include "sysemu/device_tree.h"
57
#include "sysemu/runstate.h"
58
#include "sysemu/sysemu.h"
59

60 61
#include <libfdt.h>

62 63 64 65 66
#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
67

68 69 70 71 72
static const struct MemmapEntry {
    hwaddr base;
    hwaddr size;
} sifive_u_memmap[] = {
    [SIFIVE_U_DEBUG] =    {        0x0,      0x100 },
73
    [SIFIVE_U_MROM] =     {     0x1000,    0x11000 },
74
    [SIFIVE_U_CLINT] =    {  0x2000000,    0x10000 },
75
    [SIFIVE_U_L2LIM] =    {  0x8000000,  0x2000000 },
76
    [SIFIVE_U_PLIC] =     {  0xc000000,  0x4000000 },
77
    [SIFIVE_U_PRCI] =     { 0x10000000,     0x1000 },
78 79
    [SIFIVE_U_UART0] =    { 0x10010000,     0x1000 },
    [SIFIVE_U_UART1] =    { 0x10011000,     0x1000 },
80
    [SIFIVE_U_GPIO] =     { 0x10060000,     0x1000 },
81
    [SIFIVE_U_OTP] =      { 0x10070000,     0x1000 },
82 83
    [SIFIVE_U_GEM] =      { 0x10090000,     0x2000 },
    [SIFIVE_U_GEM_MGMT] = { 0x100a0000,     0x1000 },
84
    [SIFIVE_U_DMC] =      { 0x100b0000,    0x10000 },
85 86
    [SIFIVE_U_FLASH0] =   { 0x20000000, 0x10000000 },
    [SIFIVE_U_DRAM] =     { 0x80000000,        0x0 },
87 88
};

89
#define OTP_SERIAL          1
90 91
#define GEM_REVISION        0x10070109

92
static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap,
93 94
    uint64_t mem_size, const char *cmdline)
{
95
    MachineState *ms = MACHINE(qdev_get_machine());
96 97 98 99
    void *fdt;
    int cpu;
    uint32_t *cells;
    char *nodename;
100
    char ethclk_names[] = "pclk\0hclk";
101
    uint32_t plic_phandle, prci_phandle, gpio_phandle, phandle = 1;
102
    uint32_t hfclk_phandle, rtcclk_phandle, phy_phandle;
103 104 105 106 107 108 109

    fdt = s->fdt = create_device_tree(&s->fdt_size);
    if (!fdt) {
        error_report("create_device_tree() failed");
        exit(1);
    }

110 111 112
    qemu_fdt_setprop_string(fdt, "/", "model", "SiFive HiFive Unleashed A00");
    qemu_fdt_setprop_string(fdt, "/", "compatible",
                            "sifive,hifive-unleashed-a00");
113 114 115 116 117
    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);
118
    qemu_fdt_setprop_string(fdt, "/soc", "compatible", "simple-bus");
119 120 121
    qemu_fdt_setprop_cell(fdt, "/soc", "#size-cells", 0x2);
    qemu_fdt_setprop_cell(fdt, "/soc", "#address-cells", 0x2);

122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
    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);

144 145 146 147 148 149 150 151 152 153
    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");
154 155
    qemu_fdt_setprop_cell(fdt, "/cpus", "timebase-frequency",
        SIFIVE_CLINT_TIMEBASE_FREQ);
156 157 158
    qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0x0);
    qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 0x1);

159
    for (cpu = ms->smp.cpus - 1; cpu >= 0; cpu--) {
160
        int cpu_phandle = phandle++;
161 162
        nodename = g_strdup_printf("/cpus/cpu@%d", cpu);
        char *intc = g_strdup_printf("/cpus/cpu@%d/interrupt-controller", cpu);
163
        char *isa;
164
        qemu_fdt_add_subnode(fdt, nodename);
165 166
        /* cpu 0 is the management hart that does not have mmu */
        if (cpu != 0) {
167 168 169
#if defined(TARGET_RISCV32)
            qemu_fdt_setprop_string(fdt, nodename, "mmu-type", "riscv,sv32");
#else
170
            qemu_fdt_setprop_string(fdt, nodename, "mmu-type", "riscv,sv48");
171
#endif
172 173 174 175
            isa = riscv_isa_string(&s->soc.u_cpus.harts[cpu - 1]);
        } else {
            isa = riscv_isa_string(&s->soc.e_cpus.harts[0]);
        }
176 177 178 179 180 181
        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);
182
        qemu_fdt_setprop_cell(fdt, intc, "phandle", cpu_phandle);
183 184 185 186 187 188 189 190
        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);
    }

191 192
    cells =  g_new0(uint32_t, ms->smp.cpus * 4);
    for (cpu = 0; cpu < ms->smp.cpus; cpu++) {
193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
        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",
210
        cells, ms->smp.cpus * sizeof(uint32_t) * 4);
211 212 213
    g_free(cells);
    g_free(nodename);

214 215 216 217 218 219 220 221 222 223 224
    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);

225 226 227 228 229 230 231 232 233 234 235 236 237 238 239
    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);

240
    plic_phandle = phandle++;
241 242
    cells =  g_new0(uint32_t, ms->smp.cpus * 4 - 2);
    for (cpu = 0; cpu < ms->smp.cpus; cpu++) {
243 244 245
        nodename =
            g_strdup_printf("/cpus/cpu@%d/interrupt-controller", cpu);
        uint32_t intc_phandle = qemu_fdt_get_phandle(fdt, nodename);
246 247 248 249 250 251 252 253 254 255
        /* 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);
        }
256 257 258 259 260 261 262 263 264
        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",
265
        cells, (ms->smp.cpus * 4 - 2) * sizeof(uint32_t));
266 267 268
    qemu_fdt_setprop_cells(fdt, nodename, "reg",
        0x0, memmap[SIFIVE_U_PLIC].base,
        0x0, memmap[SIFIVE_U_PLIC].size);
269
    qemu_fdt_setprop_cell(fdt, nodename, "riscv,ndev", 0x35);
270
    qemu_fdt_setprop_cell(fdt, nodename, "phandle", plic_phandle);
271 272 273 274
    plic_phandle = qemu_fdt_get_phandle(fdt, nodename);
    g_free(cells);
    g_free(nodename);

275
    gpio_phandle = phandle++;
276 277 278
    nodename = g_strdup_printf("/soc/gpio@%lx",
        (long)memmap[SIFIVE_U_GPIO].base);
    qemu_fdt_add_subnode(fdt, nodename);
279
    qemu_fdt_setprop_cell(fdt, nodename, "phandle", gpio_phandle);
280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298
    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);

299 300 301 302 303 304
    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);

305
    phy_phandle = phandle++;
306 307 308
    nodename = g_strdup_printf("/soc/ethernet@%lx",
        (long)memmap[SIFIVE_U_GEM].base);
    qemu_fdt_add_subnode(fdt, nodename);
309 310
    qemu_fdt_setprop_string(fdt, nodename, "compatible",
        "sifive,fu540-c000-gem");
311 312
    qemu_fdt_setprop_cells(fdt, nodename, "reg",
        0x0, memmap[SIFIVE_U_GEM].base,
313 314 315
        0x0, memmap[SIFIVE_U_GEM].size,
        0x0, memmap[SIFIVE_U_GEM_MGMT].base,
        0x0, memmap[SIFIVE_U_GEM_MGMT].size);
316 317
    qemu_fdt_setprop_string(fdt, nodename, "reg-names", "control");
    qemu_fdt_setprop_string(fdt, nodename, "phy-mode", "gmii");
318
    qemu_fdt_setprop_cell(fdt, nodename, "phy-handle", phy_phandle);
319 320
    qemu_fdt_setprop_cell(fdt, nodename, "interrupt-parent", plic_phandle);
    qemu_fdt_setprop_cell(fdt, nodename, "interrupts", SIFIVE_U_GEM_IRQ);
321
    qemu_fdt_setprop_cells(fdt, nodename, "clocks",
322
        prci_phandle, PRCI_CLK_GEMGXLPLL, prci_phandle, PRCI_CLK_GEMGXLPLL);
323
    qemu_fdt_setprop(fdt, nodename, "clock-names", ethclk_names,
324
        sizeof(ethclk_names));
325 326
    qemu_fdt_setprop(fdt, nodename, "local-mac-address",
        s->soc.gem.conf.macaddr.a, ETH_ALEN);
327 328
    qemu_fdt_setprop_cell(fdt, nodename, "#address-cells", 1);
    qemu_fdt_setprop_cell(fdt, nodename, "#size-cells", 0);
329 330 331 332

    qemu_fdt_add_subnode(fdt, "/aliases");
    qemu_fdt_setprop_string(fdt, "/aliases", "ethernet0", nodename);

333 334 335 336 337
    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);
338
    qemu_fdt_setprop_cell(fdt, nodename, "phandle", phy_phandle);
339
    qemu_fdt_setprop_cell(fdt, nodename, "reg", 0x0);
340 341
    g_free(nodename);

342
    nodename = g_strdup_printf("/soc/serial@%lx",
343 344 345 346 347 348
        (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);
349 350
    qemu_fdt_setprop_cells(fdt, nodename, "clocks",
        prci_phandle, PRCI_CLK_TLCLK);
351 352
    qemu_fdt_setprop_cell(fdt, nodename, "interrupt-parent", plic_phandle);
    qemu_fdt_setprop_cell(fdt, nodename, "interrupts", SIFIVE_U_UART0_IRQ);
353 354 355

    qemu_fdt_add_subnode(fdt, "/chosen");
    qemu_fdt_setprop_string(fdt, "/chosen", "stdout-path", nodename);
356 357 358
    if (cmdline) {
        qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", cmdline);
    }
359 360 361

    qemu_fdt_setprop_string(fdt, "/aliases", "serial0", nodename);

362 363 364
    g_free(nodename);
}

365 366 367 368 369 370 371 372
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);
    }
}

373
static void sifive_u_machine_init(MachineState *machine)
374 375
{
    const struct MemmapEntry *memmap = sifive_u_memmap;
376
    SiFiveUState *s = RISCV_U_MACHINE(machine);
377
    MemoryRegion *system_memory = get_system_memory();
378
    MemoryRegion *main_mem = g_new(MemoryRegion, 1);
379
    MemoryRegion *flash0 = g_new(MemoryRegion, 1);
380
    target_ulong start_addr = memmap[SIFIVE_U_DRAM].base;
381
    int i;
382

383
    /* Initialize SoC */
384
    object_initialize_child(OBJECT(machine), "soc", &s->soc, TYPE_RISCV_U_SOC);
385 386
    object_property_set_uint(OBJECT(&s->soc), "serial", s->serial,
                             &error_abort);
387
    qdev_realize(DEVICE(&s->soc), NULL, &error_abort);
388 389 390 391

    /* register RAM */
    memory_region_init_ram(main_mem, NULL, "riscv.sifive.u.ram",
                           machine->ram_size, &error_fatal);
392
    memory_region_add_subregion(system_memory, memmap[SIFIVE_U_DRAM].base,
393
                                main_mem);
394

395 396 397 398 399 400
    /* 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);

401 402 403 404
    /* register gpio-restart */
    qdev_connect_gpio_out(DEVICE(&(s->soc.gpio)), 10,
                          qemu_allocate_irq(sifive_u_machine_reset, NULL, 0));

405
    /* create device tree */
406
    create_fdt(s, memmap, machine->ram_size, machine->kernel_cmdline);
407

408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435
    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);
436

437
    if (machine->kernel_filename) {
438 439
        uint64_t kernel_entry = riscv_load_kernel(machine->kernel_filename,
                                                  NULL);
440 441 442 443 444 445

        if (machine->initrd_filename) {
            hwaddr start;
            hwaddr end = riscv_load_initrd(machine->initrd_filename,
                                           machine->ram_size, kernel_entry,
                                           &start);
446
            qemu_fdt_setprop_cell(s->fdt, "/chosen",
447
                                  "linux,initrd-start", start);
448
            qemu_fdt_setprop_cell(s->fdt, "/chosen", "linux,initrd-end",
449 450
                                  end);
        }
451 452 453 454
    }

    /* reset vector */
    uint32_t reset_vec[8] = {
455
        s->msel,                       /* MSEL pin state */
456
        0x00000297,                    /* 1:  auipc  t0, %pcrel_hi(dtb) */
457
        0x01c28593,                    /*     addi   a1, t0, %pcrel_lo(1b) */
458 459 460 461
        0xf1402573,                    /*     csrr   a0, mhartid  */
#if defined(TARGET_RISCV32)
        0x0182a283,                    /*     lw     t0, 24(t0) */
#elif defined(TARGET_RISCV64)
462
        0x0182e283,                    /*     lwu    t0, 24(t0) */
463 464 465
#endif
        0x00028067,                    /*     jr     t0 */
        0x00000000,
466
        start_addr,                    /* start: .dword */
467 468 469
                                       /* dtb: */
    };

470 471 472 473 474 475
    /* 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);
476 477

    /* copy in the device tree */
478 479 480 481 482 483 484 485 486
    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);
487 488
}

489 490 491 492 493 494 495 496 497 498 499 500 501 502
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;
}

503 504 505
static void sifive_u_machine_get_uint32_prop(Object *obj, Visitor *v,
                                             const char *name, void *opaque,
                                             Error **errp)
506 507 508 509
{
    visit_type_uint32(v, name, (uint32_t *)opaque, errp);
}

510 511 512
static void sifive_u_machine_set_uint32_prop(Object *obj, Visitor *v,
                                             const char *name, void *opaque,
                                             Error **errp)
513 514 515 516
{
    visit_type_uint32(v, name, (uint32_t *)opaque, errp);
}

517 518 519 520 521
static void sifive_u_machine_instance_init(Object *obj)
{
    SiFiveUState *s = RISCV_U_MACHINE(obj);

    s->start_in_flash = false;
522 523 524
    object_property_add_bool(obj, "start-in-flash",
                             sifive_u_machine_get_start_in_flash,
                             sifive_u_machine_set_start_in_flash);
525 526
    object_property_set_description(obj, "start-in-flash",
                                    "Set on to tell QEMU's ROM to jump to "
527 528
                                    "flash. Otherwise QEMU will jump to DRAM "
                                    "or L2LIM depending on the msel value");
529

530 531 532 533 534 535 536
    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");

537
    s->serial = OTP_SERIAL;
538
    object_property_add(obj, "serial", "uint32",
539 540
                        sifive_u_machine_get_uint32_prop,
                        sifive_u_machine_set_uint32_prop, NULL, &s->serial);
541
    object_property_set_description(obj, "serial", "Board serial number");
542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569
}

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)

570
static void sifive_u_soc_instance_init(Object *obj)
571
{
572
    MachineState *ms = MACHINE(qdev_get_machine());
573 574
    SiFiveUSoCState *s = RISCV_U_SOC(obj);

575
    object_initialize_child(obj, "e-cluster", &s->e_cluster, TYPE_CPU_CLUSTER);
576 577
    qdev_prop_set_uint32(DEVICE(&s->e_cluster), "cluster-id", 0);

578 579
    object_initialize_child(OBJECT(&s->e_cluster), "e-cpus", &s->e_cpus,
                            TYPE_RISCV_HART_ARRAY);
580 581 582 583
    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);

584
    object_initialize_child(obj, "u-cluster", &s->u_cluster, TYPE_CPU_CLUSTER);
585 586
    qdev_prop_set_uint32(DEVICE(&s->u_cluster), "cluster-id", 1);

587 588
    object_initialize_child(OBJECT(&s->u_cluster), "u-cpus", &s->u_cpus,
                            TYPE_RISCV_HART_ARRAY);
589 590 591
    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);
592

593 594 595
    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);
596
    object_initialize_child(obj, "gpio", &s->gpio, TYPE_SIFIVE_GPIO);
597 598
}

599
static void sifive_u_soc_realize(DeviceState *dev, Error **errp)
600
{
601
    MachineState *ms = MACHINE(qdev_get_machine());
602 603 604 605
    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);
606
    MemoryRegion *l2lim_mem = g_new(MemoryRegion, 1);
607 608
    char *plic_hart_config;
    size_t plic_hart_config_len;
609 610
    int i;
    NICInfo *nd = &nd_table[0];
611

612 613
    sysbus_realize(SYS_BUS_DEVICE(&s->e_cpus), &error_abort);
    sysbus_realize(SYS_BUS_DEVICE(&s->u_cpus), &error_abort);
614 615 616 617 618 619
    /*
     * 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.
     */
620 621
    qdev_realize(DEVICE(&s->e_cluster), NULL, &error_abort);
    qdev_realize(DEVICE(&s->u_cluster), NULL, &error_abort);
622 623

    /* boot rom */
624
    memory_region_init_rom(mask_rom, OBJECT(dev), "riscv.sifive.u.mrom",
625 626 627
                           memmap[SIFIVE_U_MROM].size, &error_fatal);
    memory_region_add_subregion(system_memory, memmap[SIFIVE_U_MROM].base,
                                mask_rom);
628

629 630 631 632 633 634 635 636 637 638 639 640 641 642
    /*
     * 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);

643
    /* create PLIC hart topology configuration string */
644 645
    plic_hart_config_len = (strlen(SIFIVE_U_PLIC_HART_CONFIG) + 1) *
                           ms->smp.cpus;
646
    plic_hart_config = g_malloc0(plic_hart_config_len);
647
    for (i = 0; i < ms->smp.cpus; i++) {
648
        if (i != 0) {
649 650 651 652
            strncat(plic_hart_config, "," SIFIVE_U_PLIC_HART_CONFIG,
                    plic_hart_config_len);
        } else {
            strncat(plic_hart_config, "M", plic_hart_config_len);
653 654 655 656
        }
        plic_hart_config_len -= (strlen(SIFIVE_U_PLIC_HART_CONFIG) + 1);
    }

657 658
    /* MMIO */
    s->plic = sifive_plic_create(memmap[SIFIVE_U_PLIC].base,
659
        plic_hart_config,
660 661 662 663 664 665 666 667 668
        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);
669
    g_free(plic_hart_config);
670
    sifive_uart_create(system_memory, memmap[SIFIVE_U_UART0].base,
671
        serial_hd(0), qdev_get_gpio_in(DEVICE(s->plic), SIFIVE_U_UART0_IRQ));
672 673
    sifive_uart_create(system_memory, memmap[SIFIVE_U_UART1].base,
        serial_hd(1), qdev_get_gpio_in(DEVICE(s->plic), SIFIVE_U_UART1_IRQ));
674
    sifive_clint_create(memmap[SIFIVE_U_CLINT].base,
675
        memmap[SIFIVE_U_CLINT].size, ms->smp.cpus,
676
        SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE, false);
677

678 679 680
    if (!sysbus_realize(SYS_BUS_DEVICE(&s->prci), errp)) {
        return;
    }
681 682
    sysbus_mmio_map(SYS_BUS_DEVICE(&s->prci), 0, memmap[SIFIVE_U_PRCI].base);

683
    qdev_prop_set_uint32(DEVICE(&s->gpio), "ngpio", 16);
684 685 686
    if (!sysbus_realize(SYS_BUS_DEVICE(&s->gpio), errp)) {
        return;
    }
687 688 689 690 691 692 693 694 695 696 697 698
    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));
    }

699
    qdev_prop_set_uint32(DEVICE(&s->otp), "serial", s->serial);
700 701 702
    if (!sysbus_realize(SYS_BUS_DEVICE(&s->otp), errp)) {
        return;
    }
703 704
    sysbus_mmio_map(SYS_BUS_DEVICE(&s->otp), 0, memmap[SIFIVE_U_OTP].base);

705 706 707 708
    if (nd->used) {
        qemu_check_nic_model(nd, TYPE_CADENCE_GEM);
        qdev_set_nic_properties(DEVICE(&s->gem), nd);
    }
709
    object_property_set_int(OBJECT(&s->gem), "revision", GEM_REVISION,
710
                            &error_abort);
711
    if (!sysbus_realize(SYS_BUS_DEVICE(&s->gem), errp)) {
712 713 714 715
        return;
    }
    sysbus_mmio_map(SYS_BUS_DEVICE(&s->gem), 0, memmap[SIFIVE_U_GEM].base);
    sysbus_connect_irq(SYS_BUS_DEVICE(&s->gem), 0,
716
                       qdev_get_gpio_in(DEVICE(s->plic), SIFIVE_U_GEM_IRQ));
717 718 719

    create_unimplemented_device("riscv.sifive.u.gem-mgmt",
        memmap[SIFIVE_U_GEM_MGMT].base, memmap[SIFIVE_U_GEM_MGMT].size);
720 721 722

    create_unimplemented_device("riscv.sifive.u.dmc",
        memmap[SIFIVE_U_DMC].base, memmap[SIFIVE_U_DMC].size);
723 724
}

725
static Property sifive_u_soc_props[] = {
726 727 728 729
    DEFINE_PROP_UINT32("serial", SiFiveUSoCState, serial, OTP_SERIAL),
    DEFINE_PROP_END_OF_LIST()
};

730
static void sifive_u_soc_class_init(ObjectClass *oc, void *data)
731 732 733
{
    DeviceClass *dc = DEVICE_CLASS(oc);

734 735
    device_class_set_props(dc, sifive_u_soc_props);
    dc->realize = sifive_u_soc_realize;
736 737 738 739
    /* Reason: Uses serial_hds in realize function, thus can't be used twice */
    dc->user_creatable = false;
}

740
static const TypeInfo sifive_u_soc_type_info = {
741 742 743
    .name = TYPE_RISCV_U_SOC,
    .parent = TYPE_DEVICE,
    .instance_size = sizeof(SiFiveUSoCState),
744 745
    .instance_init = sifive_u_soc_instance_init,
    .class_init = sifive_u_soc_class_init,
746 747
};

748
static void sifive_u_soc_register_types(void)
749
{
750
    type_register_static(&sifive_u_soc_type_info);
751 752
}

753
type_init(sifive_u_soc_register_types)