Merge tag 'u-boot-atmel-fixes-2020.07-a' of https://gitlab.denx.de/u-boot/custodians...
[oweals/u-boot.git] / arch / riscv / lib / bootm.c
index 9242fa891ac25795067dc3ede0c635342a258921..c4137ded834bf7e6d5c3c2a350227e8f00a9bc8b 100644 (file)
@@ -1,55 +1,68 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * Copyright (C) 2011 Andes Technology Corporation
  * Shawn Lin, Andes Technology Corporation <nobuhiro@andestech.com>
  * Macpaul Lin, Andes Technology Corporation <macpaul@andestech.com>
  * Rick Chen, Andes Technology Corporation <rick@andestech.com>
- *
- * SPDX-License-Identifier:    GPL-2.0+
  */
 
 #include <common.h>
+#include <bootstage.h>
 #include <command.h>
+#include <dm.h>
+#include <fdt_support.h>
+#include <hang.h>
+#include <log.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;
 
-int arch_fixup_fdt(void *blob)
+__weak void board_quiesce_devices(void)
 {
-       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;
-
-       if ((flag != 0) && (flag != BOOTM_STATE_OS_GO))
-               return 1;
+       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
 
-       theKernel = (void (*)(int, uint))images->ep;
+#ifdef CONFIG_USB_DEVICE
+       udc_disconnect();
+#endif
 
-       s = env_get("machid");
-       if (s) {
-               machid = simple_strtoul(s, NULL, 16);
-               printf("Using machid 0x%x from environment\n", machid);
-       }
+       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)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");
@@ -58,16 +71,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();
        }
+}
 
-       /* 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);
+#ifdef CONFIG_SMP
+       int ret;
+#endif
 
-       cleanup_before_linux();
-       if (IMAGE_ENABLE_OF_LIBFDT && images->ft_len)
-               theKernel(machid, (unsigned long)images->ft_addr);
+       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);
+               }
+       }
+}
 
-       /* does not return */
+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;
+
+       if (flag & BOOTM_STATE_OS_PREP) {
+               boot_prep_linux(images);
+               return 0;
+       }
 
-       return 1;
+       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;
+}
+
+int do_bootm_vxworks(int flag, int argc, char *const argv[],
+                    bootm_headers_t *images)
+{
+       return do_bootm_linux(flag, argc, argv, images);
 }