* 7) DMA (Direct Memory Access Controller)
* 8) SPI0 connected to an SPI flash
* 9) SPI2 connected to an SD card
+ * 10) PWM0 and PWM1
*
* This board currently generates devicetree dynamically that indicates at least
* two harts and up to five harts.
#include "hw/char/serial.h"
#include "hw/cpu/cluster.h"
#include "hw/misc/unimp.h"
+#include "hw/sd/sd.h"
#include "hw/ssi/ssi.h"
#include "target/riscv/cpu.h"
#include "hw/riscv/riscv_hart.h"
#include "hw/riscv/sifive_u.h"
#include "hw/riscv/boot.h"
#include "hw/char/sifive_uart.h"
-#include "hw/intc/sifive_clint.h"
+#include "hw/intc/riscv_aclint.h"
#include "hw/intc/sifive_plic.h"
#include "chardev/char.h"
#include "net/eth.h"
-#include "sysemu/arch_init.h"
#include "sysemu/device_tree.h"
#include "sysemu/runstate.h"
#include "sysemu/sysemu.h"
#include <libfdt.h>
+/* CLINT timebase frequency */
+#define CLINT_TIMEBASE_FREQ 1000000
+
static const MemMapEntry sifive_u_memmap[] = {
[SIFIVE_U_DEV_DEBUG] = { 0x0, 0x100 },
[SIFIVE_U_DEV_MROM] = { 0x1000, 0xf000 },
[SIFIVE_U_DEV_PRCI] = { 0x10000000, 0x1000 },
[SIFIVE_U_DEV_UART0] = { 0x10010000, 0x1000 },
[SIFIVE_U_DEV_UART1] = { 0x10011000, 0x1000 },
+ [SIFIVE_U_DEV_PWM0] = { 0x10020000, 0x1000 },
+ [SIFIVE_U_DEV_PWM1] = { 0x10021000, 0x1000 },
[SIFIVE_U_DEV_QSPI0] = { 0x10040000, 0x1000 },
[SIFIVE_U_DEV_QSPI2] = { 0x10050000, 0x1000 },
[SIFIVE_U_DEV_GPIO] = { 0x10060000, 0x1000 },
#define GEM_REVISION 0x10070109
static void create_fdt(SiFiveUState *s, const MemMapEntry *memmap,
- uint64_t mem_size, const char *cmdline, bool is_32_bit)
+ bool is_32_bit)
{
- MachineState *ms = MACHINE(qdev_get_machine());
+ MachineState *ms = MACHINE(s);
+ uint64_t mem_size = ms->ram_size;
void *fdt;
int cpu;
uint32_t *cells;
static const char * const clint_compat[2] = {
"sifive,clint0", "riscv,clint0"
};
+ static const char * const plic_compat[2] = {
+ "sifive,plic-1.0.0", "riscv,plic0"
+ };
- if (ms->dtb) {
- fdt = s->fdt = load_device_tree(ms->dtb, &s->fdt_size);
- if (!fdt) {
- error_report("load_device_tree() failed");
- exit(1);
- }
- goto update_bootargs;
- } else {
- fdt = s->fdt = create_device_tree(&s->fdt_size);
- if (!fdt) {
- error_report("create_device_tree() failed");
- exit(1);
- }
+ fdt = ms->fdt = create_device_tree(&s->fdt_size);
+ if (!fdt) {
+ error_report("create_device_tree() failed");
+ exit(1);
}
qemu_fdt_setprop_string(fdt, "/", "model", "SiFive HiFive Unleashed A00");
qemu_fdt_add_subnode(fdt, "/cpus");
qemu_fdt_setprop_cell(fdt, "/cpus", "timebase-frequency",
- SIFIVE_CLINT_TIMEBASE_FREQ);
+ CLINT_TIMEBASE_FREQ);
qemu_fdt_setprop_cell(fdt, "/cpus", "#size-cells", 0x0);
qemu_fdt_setprop_cell(fdt, "/cpus", "#address-cells", 0x1);
(long)memmap[SIFIVE_U_DEV_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_string_array(fdt, nodename, "compatible",
+ (char **)&plic_compat, ARRAY_SIZE(plic_compat));
qemu_fdt_setprop(fdt, nodename, "interrupt-controller", NULL, 0);
qemu_fdt_setprop(fdt, nodename, "interrupts-extended",
cells, (ms->smp.cpus * 4 - 2) * sizeof(uint32_t));
qemu_fdt_setprop_cells(fdt, nodename, "reg",
0x0, memmap[SIFIVE_U_DEV_PLIC].base,
0x0, memmap[SIFIVE_U_DEV_PLIC].size);
- qemu_fdt_setprop_cell(fdt, nodename, "riscv,ndev", 0x35);
+ qemu_fdt_setprop_cell(fdt, nodename, "riscv,ndev",
+ SIFIVE_U_PLIC_NUM_SOURCES - 1);
qemu_fdt_setprop_cell(fdt, nodename, "phandle", plic_phandle);
plic_phandle = qemu_fdt_get_phandle(fdt, nodename);
g_free(cells);
qemu_fdt_setprop_cell(fdt, nodename, "reg", 0x0);
g_free(nodename);
+ 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);
+
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, "/aliases", "serial0", nodename);
g_free(nodename);
-
-update_bootargs:
- if (cmdline) {
- qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", cmdline);
- }
}
static void sifive_u_machine_reset(void *opaque, int n, int level)
const MemMapEntry *memmap = sifive_u_memmap;
SiFiveUState *s = RISCV_U_MACHINE(machine);
MemoryRegion *system_memory = get_system_memory();
- MemoryRegion *main_mem = g_new(MemoryRegion, 1);
MemoryRegion *flash0 = g_new(MemoryRegion, 1);
target_ulong start_addr = memmap[SIFIVE_U_DEV_DRAM].base;
target_ulong firmware_end_addr, kernel_start_addr;
+ const char *firmware_name;
uint32_t start_addr_hi32 = 0x00000000;
int i;
uint32_t fdt_load_addr;
uint64_t kernel_entry;
DriveInfo *dinfo;
- DeviceState *flash_dev, *sd_dev;
+ BlockBackend *blk;
+ DeviceState *flash_dev, *sd_dev, *card_dev;
qemu_irq flash_cs, sd_cs;
/* Initialize SoC */
&error_abort);
object_property_set_str(OBJECT(&s->soc), "cpu-type", machine->cpu_type,
&error_abort);
- qdev_realize(DEVICE(&s->soc), NULL, &error_abort);
+ qdev_realize(DEVICE(&s->soc), NULL, &error_fatal);
/* register RAM */
- memory_region_init_ram(main_mem, NULL, "riscv.sifive.u.ram",
- machine->ram_size, &error_fatal);
memory_region_add_subregion(system_memory, memmap[SIFIVE_U_DEV_DRAM].base,
- main_mem);
+ machine->ram);
/* register QSPI0 Flash */
memory_region_init_ram(flash0, NULL, "riscv.sifive.u.flash0",
qdev_connect_gpio_out(DEVICE(&(s->soc.gpio)), 10,
qemu_allocate_irq(sifive_u_machine_reset, NULL, 0));
- /* create device tree */
- create_fdt(s, memmap, machine->ram_size, machine->kernel_cmdline,
- riscv_is_32bit(&s->soc.u_cpus));
+ /* load/create device tree */
+ if (machine->dtb) {
+ machine->fdt = load_device_tree(machine->dtb, &s->fdt_size);
+ if (!machine->fdt) {
+ error_report("load_device_tree() failed");
+ exit(1);
+ }
+ } else {
+ create_fdt(s, memmap, riscv_is_32bit(&s->soc.u_cpus));
+ }
if (s->start_in_flash) {
/*
break;
}
- if (riscv_is_32bit(&s->soc.u_cpus)) {
- firmware_end_addr = riscv_find_and_load_firmware(machine,
- "opensbi-riscv32-generic-fw_dynamic.bin",
- start_addr, NULL);
- } else {
- firmware_end_addr = riscv_find_and_load_firmware(machine,
- "opensbi-riscv64-generic-fw_dynamic.bin",
- start_addr, NULL);
- }
+ firmware_name = riscv_default_firmware_name(&s->soc.u_cpus);
+ firmware_end_addr = riscv_find_and_load_firmware(machine, firmware_name,
+ start_addr, NULL);
if (machine->kernel_filename) {
kernel_start_addr = riscv_calc_kernel_start_addr(&s->soc.u_cpus,
firmware_end_addr);
- kernel_entry = riscv_load_kernel(machine->kernel_filename,
- kernel_start_addr, NULL);
-
- if (machine->initrd_filename) {
- hwaddr start;
- hwaddr end = riscv_load_initrd(machine->initrd_filename,
- machine->ram_size, kernel_entry,
- &start);
- qemu_fdt_setprop_cell(s->fdt, "/chosen",
- "linux,initrd-start", start);
- qemu_fdt_setprop_cell(s->fdt, "/chosen", "linux,initrd-end",
- end);
- }
+ kernel_entry = riscv_load_kernel(machine, &s->soc.u_cpus,
+ kernel_start_addr, true, NULL);
} else {
/*
* If dynamic firmware is used, it doesn't know where is the next mode
kernel_entry = 0;
}
- /* Compute the fdt load address in dram */
- fdt_load_addr = riscv_load_fdt(memmap[SIFIVE_U_DEV_DRAM].base,
- machine->ram_size, s->fdt);
+ fdt_load_addr = riscv_compute_fdt_addr(memmap[SIFIVE_U_DEV_DRAM].base,
+ memmap[SIFIVE_U_DEV_DRAM].size,
+ machine);
+ riscv_load_fdt(fdt_load_addr, machine->fdt);
+
if (!riscv_is_32bit(&s->soc.u_cpus)) {
start_addr_hi32 = (uint64_t)start_addr >> 32;
}
/* reset vector */
- uint32_t reset_vec[11] = {
+ uint32_t reset_vec[12] = {
s->msel, /* MSEL pin state */
0x00000297, /* 1: auipc t0, %pcrel_hi(fw_dyn) */
- 0x02828613, /* addi a2, t0, %pcrel_lo(1b) */
+ 0x02c28613, /* addi a2, t0, %pcrel_lo(1b) */
0xf1402573, /* csrr a0, mhartid */
0,
0,
start_addr_hi32,
fdt_load_addr, /* fdt_laddr: .dword */
0x00000000,
+ 0x00000000,
/* fw_dyn: */
};
if (riscv_is_32bit(&s->soc.u_cpus)) {
/* Connect an SPI flash to SPI0 */
flash_dev = qdev_new("is25wp256");
- dinfo = drive_get_next(IF_MTD);
+ dinfo = drive_get(IF_MTD, 0, 0);
if (dinfo) {
qdev_prop_set_drive_err(flash_dev, "drive",
blk_by_legacy_dinfo(dinfo),
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);
+
+ dinfo = drive_get(IF_SD, 0, 0);
+ blk = dinfo ? blk_by_legacy_dinfo(dinfo) : NULL;
+ card_dev = qdev_new(TYPE_SD_CARD_SPI);
+ qdev_prop_set_drive_err(card_dev, "drive", blk, &error_fatal);
+ qdev_realize_and_unref(card_dev,
+ qdev_get_child_bus(sd_dev, "sd-bus"),
+ &error_fatal);
}
static bool sifive_u_machine_get_start_in_flash(Object *obj, Error **errp)
s->start_in_flash = value;
}
-static void sifive_u_machine_get_uint32_prop(Object *obj, Visitor *v,
- const char *name, void *opaque,
- Error **errp)
-{
- visit_type_uint32(v, name, (uint32_t *)opaque, errp);
-}
-
-static void sifive_u_machine_set_uint32_prop(Object *obj, Visitor *v,
- const char *name, void *opaque,
- Error **errp)
-{
- visit_type_uint32(v, name, (uint32_t *)opaque, errp);
-}
-
static void sifive_u_machine_instance_init(Object *obj)
{
SiFiveUState *s = RISCV_U_MACHINE(obj);
s->start_in_flash = false;
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_add_uint32_ptr(obj, "msel", &s->msel,
+ OBJ_PROP_FLAG_READWRITE);
object_property_set_description(obj, "msel",
"Mode Select (MSEL[3:0]) pin state");
s->serial = OTP_SERIAL;
- object_property_add(obj, "serial", "uint32",
- sifive_u_machine_get_uint32_prop,
- sifive_u_machine_set_uint32_prop, NULL, &s->serial);
+ object_property_add_uint32_ptr(obj, "serial", &s->serial,
+ OBJ_PROP_FLAG_READWRITE);
object_property_set_description(obj, "serial", "Board serial number");
}
mc->min_cpus = SIFIVE_U_MANAGEMENT_CPU_COUNT + 1;
mc->default_cpu_type = SIFIVE_U_CPU;
mc->default_cpus = mc->min_cpus;
+ mc->default_ram_id = "riscv.sifive.u.ram";
object_class_property_add_bool(oc, "start-in-flash",
sifive_u_machine_get_start_in_flash,
object_initialize_child(obj, "pdma", &s->dma, TYPE_SIFIVE_PDMA);
object_initialize_child(obj, "spi0", &s->spi0, TYPE_SIFIVE_SPI);
object_initialize_child(obj, "spi2", &s->spi2, TYPE_SIFIVE_SPI);
+ object_initialize_child(obj, "pwm0", &s->pwm[0], TYPE_SIFIVE_PWM);
+ object_initialize_child(obj, "pwm1", &s->pwm[1], TYPE_SIFIVE_PWM);
}
static void sifive_u_soc_realize(DeviceState *dev, Error **errp)
MemoryRegion *mask_rom = g_new(MemoryRegion, 1);
MemoryRegion *l2lim_mem = g_new(MemoryRegion, 1);
char *plic_hart_config;
- size_t plic_hart_config_len;
- int i;
+ int i, j;
NICInfo *nd = &nd_table[0];
qdev_prop_set_uint32(DEVICE(&s->u_cpus), "num-harts", ms->smp.cpus - 1);
qdev_prop_set_string(DEVICE(&s->u_cpus), "cpu-type", s->cpu_type);
qdev_prop_set_uint64(DEVICE(&s->u_cpus), "resetvec", 0x1004);
- sysbus_realize(SYS_BUS_DEVICE(&s->e_cpus), &error_abort);
- sysbus_realize(SYS_BUS_DEVICE(&s->u_cpus), &error_abort);
+ sysbus_realize(SYS_BUS_DEVICE(&s->e_cpus), &error_fatal);
+ sysbus_realize(SYS_BUS_DEVICE(&s->u_cpus), &error_fatal);
/*
* 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
l2lim_mem);
/* create PLIC hart topology configuration string */
- plic_hart_config_len = (strlen(SIFIVE_U_PLIC_HART_CONFIG) + 1) *
- ms->smp.cpus;
- plic_hart_config = g_malloc0(plic_hart_config_len);
- for (i = 0; i < ms->smp.cpus; i++) {
- if (i != 0) {
- strncat(plic_hart_config, "," SIFIVE_U_PLIC_HART_CONFIG,
- plic_hart_config_len);
- } else {
- strncat(plic_hart_config, "M", plic_hart_config_len);
- }
- plic_hart_config_len -= (strlen(SIFIVE_U_PLIC_HART_CONFIG) + 1);
- }
+ plic_hart_config = riscv_plic_hart_config_string(ms->smp.cpus);
/* MMIO */
s->plic = sifive_plic_create(memmap[SIFIVE_U_DEV_PLIC].base,
- plic_hart_config, 0,
+ plic_hart_config, ms->smp.cpus, 0,
SIFIVE_U_PLIC_NUM_SOURCES,
SIFIVE_U_PLIC_NUM_PRIORITIES,
SIFIVE_U_PLIC_PRIORITY_BASE,
serial_hd(0), qdev_get_gpio_in(DEVICE(s->plic), SIFIVE_U_UART0_IRQ));
sifive_uart_create(system_memory, memmap[SIFIVE_U_DEV_UART1].base,
serial_hd(1), qdev_get_gpio_in(DEVICE(s->plic), SIFIVE_U_UART1_IRQ));
- sifive_clint_create(memmap[SIFIVE_U_DEV_CLINT].base,
- memmap[SIFIVE_U_DEV_CLINT].size, 0, ms->smp.cpus,
- SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE,
- SIFIVE_CLINT_TIMEBASE_FREQ, false);
+ 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,
+ CLINT_TIMEBASE_FREQ, false);
if (!sysbus_realize(SYS_BUS_DEVICE(&s->prci), errp)) {
return;
sysbus_connect_irq(SYS_BUS_DEVICE(&s->gem), 0,
qdev_get_gpio_in(DEVICE(s->plic), SIFIVE_U_GEM_IRQ));
+ /* 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));
+ }
+ }
+
create_unimplemented_device("riscv.sifive.u.gem-mgmt",
memmap[SIFIVE_U_DEV_GEM_MGMT].base, memmap[SIFIVE_U_DEV_GEM_MGMT].size);