hw/riscv: sifive_u: Add QSPI0 controller and connect a flash

This adds the QSPI0 controller to the SoC, and connects an ISSI
25WP256 flash to it. The generation of corresponding device tree
source fragment is also added.

Since the direct memory-mapped mode is not supported by the SiFive
SPI model, the <reg> property does not populate the second group
which represents the memory mapped address of the SPI flash.

With this commit, upstream U-Boot for the SiFive HiFive Unleashed
board can boot on QEMU 'sifive_u' out of the box. This allows users
to develop and test the recommended RISC-V boot flow with a real
world use case: ZSBL (in QEMU) loads U-Boot SPL from SPI flash to
L2LIM, then U-Boot SPL loads the payload from SPI flash that is
combined with OpenSBI fw_dynamic firmware and U-Boot proper.

Specify machine property `msel` to 6 to allow booting from the SPI
flash. U-Boot spl is directly loaded via `-bios`, and subsequent
payload is stored in the SPI flash image. Example command line:

$ qemu-system-riscv64 -nographic -M sifive_u,msel=6 -smp 5 -m 8G \
    -bios u-boot-spl.bin -drive file=spi-nor.img,if=mtd

Signed-off-by: Bin Meng <bin.meng@windriver.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Message-id: 20210126060007.12904-5-bmeng.cn@gmail.com
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
This commit is contained in:
Bin Meng 2021-01-26 14:00:02 +08:00 committed by Alistair Francis
parent 0694dabe97
commit 145b299139
3 changed files with 58 additions and 0 deletions

View File

@ -52,9 +52,11 @@ config SIFIVE_U
select SIFIVE_GPIO select SIFIVE_GPIO
select SIFIVE_PDMA select SIFIVE_PDMA
select SIFIVE_PLIC select SIFIVE_PLIC
select SIFIVE_SPI
select SIFIVE_UART select SIFIVE_UART
select SIFIVE_U_OTP select SIFIVE_U_OTP
select SIFIVE_U_PRCI select SIFIVE_U_PRCI
select SSI_M25P80
select UNIMP select UNIMP
config SPIKE config SPIKE

View File

@ -15,6 +15,7 @@
* 5) OTP (One-Time Programmable) memory with stored serial number * 5) OTP (One-Time Programmable) memory with stored serial number
* 6) GEM (Gigabit Ethernet Controller) and management block * 6) GEM (Gigabit Ethernet Controller) and management block
* 7) DMA (Direct Memory Access Controller) * 7) DMA (Direct Memory Access Controller)
* 8) SPI0 connected to an SPI flash
* *
* This board currently generates devicetree dynamically that indicates at least * This board currently generates devicetree dynamically that indicates at least
* two harts and up to five harts. * two harts and up to five harts.
@ -44,6 +45,7 @@
#include "hw/char/serial.h" #include "hw/char/serial.h"
#include "hw/cpu/cluster.h" #include "hw/cpu/cluster.h"
#include "hw/misc/unimp.h" #include "hw/misc/unimp.h"
#include "hw/ssi/ssi.h"
#include "target/riscv/cpu.h" #include "target/riscv/cpu.h"
#include "hw/riscv/riscv_hart.h" #include "hw/riscv/riscv_hart.h"
#include "hw/riscv/sifive_u.h" #include "hw/riscv/sifive_u.h"
@ -74,6 +76,7 @@ static const struct MemmapEntry {
[SIFIVE_U_DEV_PRCI] = { 0x10000000, 0x1000 }, [SIFIVE_U_DEV_PRCI] = { 0x10000000, 0x1000 },
[SIFIVE_U_DEV_UART0] = { 0x10010000, 0x1000 }, [SIFIVE_U_DEV_UART0] = { 0x10010000, 0x1000 },
[SIFIVE_U_DEV_UART1] = { 0x10011000, 0x1000 }, [SIFIVE_U_DEV_UART1] = { 0x10011000, 0x1000 },
[SIFIVE_U_DEV_QSPI0] = { 0x10040000, 0x1000 },
[SIFIVE_U_DEV_GPIO] = { 0x10060000, 0x1000 }, [SIFIVE_U_DEV_GPIO] = { 0x10060000, 0x1000 },
[SIFIVE_U_DEV_OTP] = { 0x10070000, 0x1000 }, [SIFIVE_U_DEV_OTP] = { 0x10070000, 0x1000 },
[SIFIVE_U_DEV_GEM] = { 0x10090000, 0x2000 }, [SIFIVE_U_DEV_GEM] = { 0x10090000, 0x2000 },
@ -342,6 +345,32 @@ static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap,
"sifive,fu540-c000-ccache"); "sifive,fu540-c000-ccache");
g_free(nodename); g_free(nodename);
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);
phy_phandle = phandle++; phy_phandle = phandle++;
nodename = g_strdup_printf("/soc/ethernet@%lx", nodename = g_strdup_printf("/soc/ethernet@%lx",
(long)memmap[SIFIVE_U_DEV_GEM].base); (long)memmap[SIFIVE_U_DEV_GEM].base);
@ -439,6 +468,9 @@ static void sifive_u_machine_init(MachineState *machine)
int i; int i;
uint32_t fdt_load_addr; uint32_t fdt_load_addr;
uint64_t kernel_entry; uint64_t kernel_entry;
DriveInfo *dinfo;
DeviceState *flash_dev;
qemu_irq flash_cs;
/* Initialize SoC */ /* Initialize SoC */
object_initialize_child(OBJECT(machine), "soc", &s->soc, TYPE_RISCV_U_SOC); object_initialize_child(OBJECT(machine), "soc", &s->soc, TYPE_RISCV_U_SOC);
@ -571,6 +603,19 @@ static void sifive_u_machine_init(MachineState *machine)
riscv_rom_copy_firmware_info(machine, memmap[SIFIVE_U_DEV_MROM].base, riscv_rom_copy_firmware_info(machine, memmap[SIFIVE_U_DEV_MROM].base,
memmap[SIFIVE_U_DEV_MROM].size, memmap[SIFIVE_U_DEV_MROM].size,
sizeof(reset_vec), kernel_entry); sizeof(reset_vec), kernel_entry);
/* Connect an SPI flash to SPI0 */
flash_dev = qdev_new("is25wp256");
dinfo = drive_get_next(IF_MTD);
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);
} }
static bool sifive_u_machine_get_start_in_flash(Object *obj, Error **errp) static bool sifive_u_machine_get_start_in_flash(Object *obj, Error **errp)
@ -680,6 +725,7 @@ static void sifive_u_soc_instance_init(Object *obj)
object_initialize_child(obj, "gem", &s->gem, TYPE_CADENCE_GEM); object_initialize_child(obj, "gem", &s->gem, TYPE_CADENCE_GEM);
object_initialize_child(obj, "gpio", &s->gpio, TYPE_SIFIVE_GPIO); object_initialize_child(obj, "gpio", &s->gpio, TYPE_SIFIVE_GPIO);
object_initialize_child(obj, "pdma", &s->dma, TYPE_SIFIVE_PDMA); object_initialize_child(obj, "pdma", &s->dma, TYPE_SIFIVE_PDMA);
object_initialize_child(obj, "spi0", &s->spi0, TYPE_SIFIVE_SPI);
} }
static void sifive_u_soc_realize(DeviceState *dev, Error **errp) static void sifive_u_soc_realize(DeviceState *dev, Error **errp)
@ -827,6 +873,12 @@ static void sifive_u_soc_realize(DeviceState *dev, Error **errp)
create_unimplemented_device("riscv.sifive.u.l2cc", create_unimplemented_device("riscv.sifive.u.l2cc",
memmap[SIFIVE_U_DEV_L2CC].base, memmap[SIFIVE_U_DEV_L2CC].size); memmap[SIFIVE_U_DEV_L2CC].base, memmap[SIFIVE_U_DEV_L2CC].size);
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));
} }
static Property sifive_u_soc_props[] = { static Property sifive_u_soc_props[] = {

View File

@ -26,6 +26,7 @@
#include "hw/gpio/sifive_gpio.h" #include "hw/gpio/sifive_gpio.h"
#include "hw/misc/sifive_u_otp.h" #include "hw/misc/sifive_u_otp.h"
#include "hw/misc/sifive_u_prci.h" #include "hw/misc/sifive_u_prci.h"
#include "hw/ssi/sifive_spi.h"
#define TYPE_RISCV_U_SOC "riscv.sifive.u.soc" #define TYPE_RISCV_U_SOC "riscv.sifive.u.soc"
#define RISCV_U_SOC(obj) \ #define RISCV_U_SOC(obj) \
@ -45,6 +46,7 @@ typedef struct SiFiveUSoCState {
SIFIVEGPIOState gpio; SIFIVEGPIOState gpio;
SiFiveUOTPState otp; SiFiveUOTPState otp;
SiFivePDMAState dma; SiFivePDMAState dma;
SiFiveSPIState spi0;
CadenceGEMState gem; CadenceGEMState gem;
uint32_t serial; uint32_t serial;
@ -82,6 +84,7 @@ enum {
SIFIVE_U_DEV_UART0, SIFIVE_U_DEV_UART0,
SIFIVE_U_DEV_UART1, SIFIVE_U_DEV_UART1,
SIFIVE_U_DEV_GPIO, SIFIVE_U_DEV_GPIO,
SIFIVE_U_DEV_QSPI0,
SIFIVE_U_DEV_OTP, SIFIVE_U_DEV_OTP,
SIFIVE_U_DEV_DMC, SIFIVE_U_DEV_DMC,
SIFIVE_U_DEV_FLASH0, SIFIVE_U_DEV_FLASH0,
@ -120,6 +123,7 @@ enum {
SIFIVE_U_PDMA_IRQ5 = 28, SIFIVE_U_PDMA_IRQ5 = 28,
SIFIVE_U_PDMA_IRQ6 = 29, SIFIVE_U_PDMA_IRQ6 = 29,
SIFIVE_U_PDMA_IRQ7 = 30, SIFIVE_U_PDMA_IRQ7 = 30,
SIFIVE_U_QSPI0_IRQ = 51,
SIFIVE_U_GEM_IRQ = 0x35 SIFIVE_U_GEM_IRQ = 0x35
}; };