common: Move hang() to the same header as panic()
[oweals/u-boot.git] / arch / riscv / lib / bootm.c
index 2610a57bbff32e6d9f9c0d63840177c43973bfeb..fad16901c5f2a032019b5a73d412aa9b510b6f45 100644 (file)
@@ -8,10 +8,17 @@
 
 #include <common.h>
 #include <command.h>
+#include <dm.h>
+#include <fdt_support.h>
+#include <hang.h>
+#include <dm/root.h>
 #include <image.h>
-#include <u-boot/zlib.h>
 #include <asm/byteorder.h>
-#include <asm/bootm.h>
+#include <asm/csr.h>
+#include <asm/smp.h>
+#include <dm/device.h>
+#include <dm/root.h>
+#include <u-boot/zlib.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -24,35 +31,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)
 {
-       bd_t    *bd = gd->bd;
-       char    *s;
-       int     machid = bd->bi_arch_number;
-       void    (*theKernel)(int arch, uint params);
-
-       /*
-        * 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
 
-       theKernel = (void (*)(int, uint))images->ep;
+       board_quiesce_devices();
 
-       s = env_get("machid");
-       if (s) {
-               machid = simple_strtoul(s, NULL, 16);
-               printf("Using machid 0x%x from environment\n", machid);
-       }
-
-       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)theKernel);
+       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");
@@ -61,16 +74,66 @@ 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();
+       }
+}
+
+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);
+#ifdef CONFIG_SMP
+       int ret;
+#endif
+
+       kernel = (void (*)(ulong, void *))images->ep;
+
+       bootstage_mark(BOOTSTAGE_ID_RUN_OS);
+
+       debug("## Transferring control to kernel (at address %08lx) ...\n",
+             (ulong)kernel);
+
+       announce_and_cleanup(fake);
+
+       if (!fake) {
+               if (IMAGE_ENABLE_OF_LIBFDT && images->ft_len) {
+#ifdef CONFIG_SMP
+                       ret = smp_call_function(images->ep,
+                                               (ulong)images->ft_addr, 0, 0);
+                       if (ret)
+                               hang();
+#endif
+                       kernel(gd->arch.boot_hart, images->ft_addr);
+               }
        }
+}
 
-       /* we assume that the kernel is in place */
-       printf("\nStarting kernel ...\n\n");
+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;
 
-       cleanup_before_linux();
-       if (IMAGE_ENABLE_OF_LIBFDT && images->ft_len)
-               theKernel(machid, (unsigned long)images->ft_addr);
+       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;
+       }
 
-       /* does not return */
+       boot_prep_linux(images);
+       boot_jump_linux(images, flag);
+       return 0;
+}
 
-       return 1;
+int do_bootm_vxworks(int flag, int argc, char * const argv[],
+                    bootm_headers_t *images)
+{
+       return do_bootm_linux(flag, argc, argv, images);
 }