diff mbox series

[13/15] hw/riscv: sifive_u: Support different boot source per MSEL pin state

Message ID 1591625864-31494-14-git-send-email-bmeng.cn@gmail.com
State New
Headers show
Series hw/riscv: sifive_u: Add GPIO and Mode Select (MSEL[3:0]) support | expand

Commit Message

Bin Meng June 8, 2020, 2:17 p.m. UTC
From: Bin Meng <bin.meng@windriver.com>

SiFive FU540 SoC supports booting from several sources, which are
controlled using the Mode Select (MSEL[3:0]) pins on the chip.
Typically, the boot process runs through several stages before it
begins execution of user-provided programs.

The SoC supports booting from memory-mapped QSPI flash, which is
how start_in_flash property is used for at present. This matches
MSEL = 1 configuration (QSPI0).

Typical booting flows involve the Zeroth Stage Boot Loader (ZSBL).
It's not necessary for QEMU to implement the full ZSBL ROM codes,
because we know ZSBL downloads the next stage program into the L2
LIM at address 0x8000000 and executes from there. We can bypass
the whole ZSBL execution and use "-bios" to load the next stage
program directly if MSEL indicates a ZSBL booting flow.

Signed-off-by: Bin Meng <bin.meng@windriver.com>
---

 hw/riscv/sifive_u.c         | 39 +++++++++++++++++++++++++++++++--------
 include/hw/riscv/sifive_u.h |  6 ++++++
 2 files changed, 37 insertions(+), 8 deletions(-)

Comments

Alistair Francis June 15, 2020, 7:04 p.m. UTC | #1
On Mon, Jun 8, 2020 at 7:28 AM Bin Meng <bmeng.cn@gmail.com> wrote:
>
> From: Bin Meng <bin.meng@windriver.com>
>
> SiFive FU540 SoC supports booting from several sources, which are
> controlled using the Mode Select (MSEL[3:0]) pins on the chip.
> Typically, the boot process runs through several stages before it
> begins execution of user-provided programs.
>
> The SoC supports booting from memory-mapped QSPI flash, which is
> how start_in_flash property is used for at present. This matches
> MSEL = 1 configuration (QSPI0).
>
> Typical booting flows involve the Zeroth Stage Boot Loader (ZSBL).
> It's not necessary for QEMU to implement the full ZSBL ROM codes,
> because we know ZSBL downloads the next stage program into the L2
> LIM at address 0x8000000 and executes from there. We can bypass
> the whole ZSBL execution and use "-bios" to load the next stage
> program directly if MSEL indicates a ZSBL booting flow.
>
> Signed-off-by: Bin Meng <bin.meng@windriver.com>

Reviewed-by: Alistair Francis <alistair.francis@wdc.com>

Alistair

> ---
>
>  hw/riscv/sifive_u.c         | 39 +++++++++++++++++++++++++++++++--------
>  include/hw/riscv/sifive_u.h |  6 ++++++
>  2 files changed, 37 insertions(+), 8 deletions(-)
>
> diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c
> index 0a86ffc..f64aa52 100644
> --- a/hw/riscv/sifive_u.c
> +++ b/hw/riscv/sifive_u.c
> @@ -408,8 +408,34 @@ static void sifive_u_machine_init(MachineState *machine)
>      /* create device tree */
>      create_fdt(s, memmap, machine->ram_size, machine->kernel_cmdline);
>
> -    riscv_find_and_load_firmware(machine, BIOS_FILENAME,
> -                                 memmap[SIFIVE_U_DRAM].base, NULL);
> +    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);
>
>      if (machine->kernel_filename) {
>          uint64_t kernel_entry = riscv_load_kernel(machine->kernel_filename,
> @@ -427,13 +453,9 @@ static void sifive_u_machine_init(MachineState *machine)
>          }
>      }
>
> -    if (s->start_in_flash) {
> -        start_addr = memmap[SIFIVE_U_FLASH0].base;
> -    }
> -
>      /* reset vector */
>      uint32_t reset_vec[8] = {
> -        0x00000000,
> +        s->msel,                       /* MSEL pin state */
>          0x00000297,                    /* 1:  auipc  t0, %pcrel_hi(dtb) */
>          0x01c28593,                    /*     addi   a1, t0, %pcrel_lo(1b) */
>          0xf1402573,                    /*     csrr   a0, mhartid  */
> @@ -505,7 +527,8 @@ static void sifive_u_machine_instance_init(Object *obj)
>                               sifive_u_machine_set_start_in_flash);
>      object_property_set_description(obj, "start-in-flash",
>                                      "Set on to tell QEMU's ROM to jump to "
> -                                    "flash. Otherwise QEMU will jump to DRAM");
> +                                    "flash. Otherwise QEMU will jump to DRAM "
> +                                    "or L2LIM depending on the msel value");
>
>      s->msel = 0;
>      object_property_add(obj, "msel", "uint32",
> diff --git a/include/hw/riscv/sifive_u.h b/include/hw/riscv/sifive_u.h
> index d82cfe0..5d80f91 100644
> --- a/include/hw/riscv/sifive_u.h
> +++ b/include/hw/riscv/sifive_u.h
> @@ -111,6 +111,12 @@ enum {
>      SIFIVE_U_RTCCLK_FREQ = 1000000
>  };
>
> +enum {
> +    MSEL_MEMMAP_QSPI0_FLASH = 1,
> +    MSEL_L2LIM_QSPI0_FLASH = 6,
> +    MSEL_L2LIM_QSPI2_SD = 11
> +};
> +
>  #define SIFIVE_U_MANAGEMENT_CPU_COUNT   1
>  #define SIFIVE_U_COMPUTE_CPU_COUNT      4
>
> --
> 2.7.4
>
>
diff mbox series

Patch

diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c
index 0a86ffc..f64aa52 100644
--- a/hw/riscv/sifive_u.c
+++ b/hw/riscv/sifive_u.c
@@ -408,8 +408,34 @@  static void sifive_u_machine_init(MachineState *machine)
     /* create device tree */
     create_fdt(s, memmap, machine->ram_size, machine->kernel_cmdline);
 
-    riscv_find_and_load_firmware(machine, BIOS_FILENAME,
-                                 memmap[SIFIVE_U_DRAM].base, NULL);
+    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);
 
     if (machine->kernel_filename) {
         uint64_t kernel_entry = riscv_load_kernel(machine->kernel_filename,
@@ -427,13 +453,9 @@  static void sifive_u_machine_init(MachineState *machine)
         }
     }
 
-    if (s->start_in_flash) {
-        start_addr = memmap[SIFIVE_U_FLASH0].base;
-    }
-
     /* reset vector */
     uint32_t reset_vec[8] = {
-        0x00000000,
+        s->msel,                       /* MSEL pin state */
         0x00000297,                    /* 1:  auipc  t0, %pcrel_hi(dtb) */
         0x01c28593,                    /*     addi   a1, t0, %pcrel_lo(1b) */
         0xf1402573,                    /*     csrr   a0, mhartid  */
@@ -505,7 +527,8 @@  static void sifive_u_machine_instance_init(Object *obj)
                              sifive_u_machine_set_start_in_flash);
     object_property_set_description(obj, "start-in-flash",
                                     "Set on to tell QEMU's ROM to jump to "
-                                    "flash. Otherwise QEMU will jump to DRAM");
+                                    "flash. Otherwise QEMU will jump to DRAM "
+                                    "or L2LIM depending on the msel value");
 
     s->msel = 0;
     object_property_add(obj, "msel", "uint32",
diff --git a/include/hw/riscv/sifive_u.h b/include/hw/riscv/sifive_u.h
index d82cfe0..5d80f91 100644
--- a/include/hw/riscv/sifive_u.h
+++ b/include/hw/riscv/sifive_u.h
@@ -111,6 +111,12 @@  enum {
     SIFIVE_U_RTCCLK_FREQ = 1000000
 };
 
+enum {
+    MSEL_MEMMAP_QSPI0_FLASH = 1,
+    MSEL_L2LIM_QSPI0_FLASH = 6,
+    MSEL_L2LIM_QSPI2_SD = 11
+};
+
 #define SIFIVE_U_MANAGEMENT_CPU_COUNT   1
 #define SIFIVE_U_COMPUTE_CPU_COUNT      4