riscv: align bootm implementation with that of other architectures
authorLukas Auer <lukas.auer@aisec.fraunhofer.de>
Thu, 22 Nov 2018 10:26:32 +0000 (11:26 +0100)
committerAndes <uboot@andestech.com>
Mon, 26 Nov 2018 05:57:32 +0000 (13:57 +0800)
The bootm implementation of RISC-V diverges from that of other
architectures. Update it to match the implementation of other
architectures. The ARM implementation is used as a reference.

This adds the following features and changes to RISC-V.
* Add support for the BOOTM_STATE_OS_FAKE_GO command
* Call the remove function on devices with the removal flag set before
booting Linux
* Force disconnect USB devices from the host before booting Linux
* Print and add bootstage information to the device tree before booting
Linux

Signed-off-by: Lukas Auer <lukas.auer@aisec.fraunhofer.de>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
arch/riscv/lib/bootm.c

index 2b5ccce9338ef16ec32694fd50f4a5a9f690d3e7..124aeefff83cf29acad2f001fab02a0dc222ac1c 100644 (file)
@@ -8,6 +8,8 @@
 
 #include <common.h>
 #include <command.h>
+#include <dm.h>
+#include <dm/root.h>
 #include <image.h>
 #include <asm/byteorder.h>
 #include <asm/csr.h>
@@ -26,26 +28,41 @@ int arch_fixup_fdt(void *blob)
        return 0;
 }
 
-int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images)
+/**
+ * announce_and_cleanup() - Print message and prepare for kernel boot
+ *
+ * @fake: non-zero to do everything except actually boot
+ */
+static void announce_and_cleanup(int fake)
 {
-       void    (*kernel)(ulong hart, void *dtb);
-
-       /*
-        * allow the PREP bootm subcommand, it is required for bootm to work
-        */
-       if (flag & BOOTM_STATE_OS_PREP)
-               return 0;
+       printf("\nStarting kernel ...%s\n\n", fake ?
+               "(fake run for tracing)" : "");
+       bootstage_mark_name(BOOTSTAGE_ID_BOOTM_HANDOFF, "start_kernel");
+#ifdef CONFIG_BOOTSTAGE_FDT
+       bootstage_fdt_add_report();
+#endif
+#ifdef CONFIG_BOOTSTAGE_REPORT
+       bootstage_report();
+#endif
 
-       if ((flag != 0) && (flag != BOOTM_STATE_OS_GO))
-               return 1;
+#ifdef CONFIG_USB_DEVICE
+       udc_disconnect();
+#endif
 
-       kernel = (void (*)(ulong, void *))images->ep;
+       board_quiesce_devices();
 
-       bootstage_mark(BOOTSTAGE_ID_RUN_OS);
+       /*
+        * Call remove function of all devices with a removal flag set.
+        * This may be useful for last-stage operations, like cancelling
+        * of DMA operation or releasing device internal buffers.
+        */
+       dm_remove_devices_flags(DM_REMOVE_ACTIVE_ALL);
 
-       debug("## Transferring control to Linux (at address %08lx) ...\n",
-              (ulong)kernel);
+       cleanup_before_linux();
+}
 
+static void boot_prep_linux(bootm_headers_t *images)
+{
        if (IMAGE_ENABLE_OF_LIBFDT && images->ft_len) {
 #ifdef CONFIG_OF_LIBFDT
                debug("using: FDT\n");
@@ -54,24 +71,50 @@ int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images)
                        hang();
                }
 #endif
+       } else {
+               printf("Device tree not found or missing FDT support\n");
+               hang();
        }
+}
 
-       /* we assume that the kernel is in place */
-       printf("\nStarting kernel ...\n\n");
+static void boot_jump_linux(bootm_headers_t *images, int flag)
+{
+       void (*kernel)(ulong hart, void *dtb);
+       int fake = (flag & BOOTM_STATE_OS_FAKE_GO);
 
-       /*
-        * Call remove function of all devices with a removal flag set.
-        * This may be useful for last-stage operations, like cancelling
-        * of DMA operation or releasing device internal buffers.
-        */
-       dm_remove_devices_flags(DM_REMOVE_ACTIVE_ALL);
+       kernel = (void (*)(ulong, void *))images->ep;
 
-       cleanup_before_linux();
+       bootstage_mark(BOOTSTAGE_ID_RUN_OS);
+
+       debug("## Transferring control to Linux (at address %08lx) ...\n",
+             (ulong)kernel);
 
-       if (IMAGE_ENABLE_OF_LIBFDT && images->ft_len)
-               kernel(csr_read(mhartid), images->ft_addr);
+       announce_and_cleanup(fake);
 
-       /* does not return */
+       if (!fake) {
+               if (IMAGE_ENABLE_OF_LIBFDT && images->ft_len)
+                       kernel(csr_read(mhartid), images->ft_addr);
+       }
+}
+
+int do_bootm_linux(int flag, int argc, char * const argv[],
+                  bootm_headers_t *images)
+{
+       /* No need for those on RISC-V */
+       if (flag & BOOTM_STATE_OS_BD_T || flag & BOOTM_STATE_OS_CMDLINE)
+               return -1;
 
-       return 1;
+       if (flag & BOOTM_STATE_OS_PREP) {
+               boot_prep_linux(images);
+               return 0;
+       }
+
+       if (flag & (BOOTM_STATE_OS_GO | BOOTM_STATE_OS_FAKE_GO)) {
+               boot_jump_linux(images, flag);
+               return 0;
+       }
+
+       boot_prep_linux(images);
+       boot_jump_linux(images, flag);
+       return 0;
 }