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 44ce38b614281a3a9e91b3e216958de800d945cd..c4137ded834bf7e6d5c3c2a350227e8f00a9bc8b 100644 (file)
@@ -1,79 +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;
 }
 
-#if defined(CONFIG_SETUP_MEMORY_TAGS) || \
-       defined(CONFIG_CMDLINE_TAG) || \
-       defined(CONFIG_INITRD_TAG) || \
-       defined(CONFIG_SERIAL_TAG) || \
-       defined(CONFIG_REVISION_TAG)
-static void setup_start_tag(bd_t *bd);
-
-# ifdef CONFIG_SETUP_MEMORY_TAGS
-static void setup_memory_tags(bd_t *bd);
-# endif
-static void setup_commandline_tag(bd_t *bd, char *commandline);
-
-# ifdef CONFIG_INITRD_TAG
-static void setup_initrd_tag(bd_t *bd, ulong initrd_start, ulong initrd_end);
-# endif
-static void setup_end_tag(bd_t *bd);
-
-static struct tag *params;
-#endif /* CONFIG_SETUP_MEMORY_TAGS || CONFIG_CMDLINE_TAG || CONFIG_INITRD_TAG */
-
-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 zero, int arch, uint params);
+       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
 
-#ifdef CONFIG_CMDLINE_TAG
-       char *commandline = env_get("bootargs");
+#ifdef CONFIG_USB_DEVICE
+       udc_disconnect();
 #endif
 
+       board_quiesce_devices();
+
        /*
-        * allow the PREP bootm subcommand, it is required for bootm to work
+        * 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.
         */
-       if (flag & BOOTM_STATE_OS_PREP)
-               return 0;
-
-       if ((flag != 0) && (flag != BOOTM_STATE_OS_GO))
-               return 1;
-
-       theKernel = (void (*)(int, int, uint))images->ep;
+       dm_remove_devices_flags(DM_REMOVE_ACTIVE_ALL);
 
-       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);
-
-       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");
@@ -82,167 +71,66 @@ int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images)
                        hang();
                }
 #endif
-       } else if (BOOTM_ENABLE_TAGS) {
-#if defined(CONFIG_SETUP_MEMORY_TAGS) || \
-       defined(CONFIG_CMDLINE_TAG) || \
-       defined(CONFIG_INITRD_TAG) || \
-       defined(CONFIG_SERIAL_TAG) || \
-       defined(CONFIG_REVISION_TAG)
-       setup_start_tag(bd);
-#ifdef CONFIG_SERIAL_TAG
-       setup_serial_tag(&params);
-#endif
-#ifdef CONFIG_REVISION_TAG
-       setup_revision_tag(&params);
-#endif
-#ifdef CONFIG_SETUP_MEMORY_TAGS
-       setup_memory_tags(bd);
-#endif
-#ifdef CONFIG_CMDLINE_TAG
-       setup_commandline_tag(bd, commandline);
-#endif
-#ifdef CONFIG_INITRD_TAG
-       if (images->rd_start && images->rd_end)
-               setup_initrd_tag(bd, images->rd_start, images->rd_end);
-#endif
-       setup_end_tag(bd);
-#endif
-
-       /* we assume that the kernel is in place */
-       printf("\nStarting kernel ...\n\n");
-
-#ifdef CONFIG_USB_DEVICE
-       {
-               extern void udc_disconnect(void);
-               udc_disconnect();
-       }
-#endif
+       } else {
+               printf("Device tree not found or missing FDT support\n");
+               hang();
        }
-       cleanup_before_linux();
-       if (IMAGE_ENABLE_OF_LIBFDT && images->ft_len)
-               theKernel(0, machid, (unsigned long)images->ft_addr);
-       else
-       theKernel(0, machid, bd->bi_boot_params);
-       /* does not return */
-
-       return 1;
 }
 
-#if defined(CONFIG_SETUP_MEMORY_TAGS) || \
-       defined(CONFIG_CMDLINE_TAG) || \
-       defined(CONFIG_INITRD_TAG) || \
-       defined(CONFIG_SERIAL_TAG) || \
-       defined(CONFIG_REVISION_TAG)
-static void setup_start_tag(bd_t *bd)
+static void boot_jump_linux(bootm_headers_t *images, int flag)
 {
-       params = (struct tag *)bd->bi_boot_params;
-
-       params->hdr.tag = ATAG_CORE;
-       params->hdr.size = tag_size(tag_core);
-
-       params->u.core.flags = 0;
-       params->u.core.pagesize = 0;
-       params->u.core.rootdev = 0;
+       void (*kernel)(ulong hart, void *dtb);
+       int fake = (flag & BOOTM_STATE_OS_FAKE_GO);
+#ifdef CONFIG_SMP
+       int ret;
+#endif
 
-       params = tag_next(params);
-}
+       kernel = (void (*)(ulong, void *))images->ep;
 
-#ifdef CONFIG_SETUP_MEMORY_TAGS
-static void setup_memory_tags(bd_t *bd)
-{
-       int i;
+       bootstage_mark(BOOTSTAGE_ID_RUN_OS);
 
-       for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
-               params->hdr.tag = ATAG_MEM;
-               params->hdr.size = tag_size(tag_mem32);
+       debug("## Transferring control to kernel (at address %08lx) ...\n",
+             (ulong)kernel);
 
-               params->u.mem.start = bd->bi_dram[i].start;
-               params->u.mem.size = bd->bi_dram[i].size;
+       announce_and_cleanup(fake);
 
-               params = tag_next(params);
+       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);
+               }
        }
 }
-#endif /* CONFIG_SETUP_MEMORY_TAGS */
-
-static void setup_commandline_tag(bd_t *bd, char *commandline)
-{
-       char *p;
-
-       if (!commandline)
-               return;
-
-       /* eat leading white space */
-       for (p = commandline; *p == ' '; p++)
-               ;
-
-       /* skip non-existent command lines so the kernel will still
-        * use its default command line.
-        */
-       if (*p == '\0')
-               return;
-
-       params->hdr.tag = ATAG_CMDLINE;
-       params->hdr.size =
-               (sizeof(struct tag_header) + strlen(p) + 1 + 4) >> 2;
-
-       strcpy(params->u.cmdline.cmdline, p)
-               ;
-
-       params = tag_next(params);
-}
 
-#ifdef CONFIG_INITRD_TAG
-static void setup_initrd_tag(bd_t *bd, ulong initrd_start, ulong initrd_end)
+int do_bootm_linux(int flag, int argc, char *const argv[],
+                  bootm_headers_t *images)
 {
-       /* an ATAG_INITRD node tells the kernel where the compressed
-        * ramdisk can be found. ATAG_RDIMG is a better name, actually.
-        */
-       params->hdr.tag = ATAG_INITRD2;
-       params->hdr.size = tag_size(tag_initrd);
+       /* No need for those on RISC-V */
+       if (flag & BOOTM_STATE_OS_BD_T || flag & BOOTM_STATE_OS_CMDLINE)
+               return -1;
 
-       params->u.initrd.start = initrd_start;
-       params->u.initrd.size = initrd_end - initrd_start;
-
-       params = tag_next(params);
-}
-#endif /* CONFIG_INITRD_TAG */
+       if (flag & BOOTM_STATE_OS_PREP) {
+               boot_prep_linux(images);
+               return 0;
+       }
 
-#ifdef CONFIG_SERIAL_TAG
-void setup_serial_tag(struct tag **tmp)
-{
-       struct tag *params;
-       struct tag_serialnr serialnr;
-       void get_board_serial(struct tag_serialnr *serialnr);
-
-       params = *tmp;
-       get_board_serial(&serialnr);
-       params->hdr.tag = ATAG_SERIAL;
-       params->hdr.size = tag_size(tag_serialnr);
-       params->u.serialnr.low = serialnr.low;
-       params->u.serialnr.high = serialnr.high;
-       params = tag_next(params);
-       *tmp = params;
-}
-#endif
+       if (flag & (BOOTM_STATE_OS_GO | BOOTM_STATE_OS_FAKE_GO)) {
+               boot_jump_linux(images, flag);
+               return 0;
+       }
 
-#ifdef CONFIG_REVISION_TAG
-void setup_revision_tag(struct tag **in_params)
-{
-       u32 rev;
-       u32 get_board_rev(void);
-
-       rev = get_board_rev();
-       params->hdr.tag = ATAG_REVISION;
-       params->hdr.size = tag_size(tag_revision);
-       params->u.revision.rev = rev;
-       params = tag_next(params);
+       boot_prep_linux(images);
+       boot_jump_linux(images, flag);
+       return 0;
 }
-#endif  /* CONFIG_REVISION_TAG */
 
-static void setup_end_tag(bd_t *bd)
+int do_bootm_vxworks(int flag, int argc, char *const argv[],
+                    bootm_headers_t *images)
 {
-       params->hdr.tag = ATAG_NONE;
-       params->hdr.size = 0;
+       return do_bootm_linux(flag, argc, argv, images);
 }
-
-#endif /* CONFIG_SETUP_MEMORY_TAGS || CONFIG_CMDLINE_TAG || CONFIG_INITRD_TAG */