Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 | // 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> */ #include <bootstage.h> #include <bootm.h> #include <command.h> #include <dm.h> #include <fdt_support.h> #include <hang.h> #include <log.h> #include <asm/global_data.h> #include <dm/root.h> #include <image.h> #include <asm/byteorder.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; __weak void board_quiesce_devices(void) { } /** * 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) { 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 #if CONFIG_IS_ENABLED(BOOTSTAGE_REPORT) bootstage_report(); #endif board_quiesce_devices(); /* * 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_active(); cleanup_before_linux(); } static void boot_prep_linux(struct bootm_headers *images) { if (CONFIG_IS_ENABLED(OF_LIBFDT) && IS_ENABLED(CONFIG_LMB) && images->ft_len) { debug("using: FDT\n"); if (image_setup_linux(images)) { printf("FDT creation failed! hanging..."); hang(); } } else { printf("Device tree not found or missing FDT support\n"); hang(); } } static void boot_jump_linux(struct bootm_headers *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 (CONFIG_IS_ENABLED(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); } } } int do_bootm_linux(int flag, struct bootm_info *bmi) { struct bootm_headers *images = bmi->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; } 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, struct bootm_info *bmi) { return do_bootm_linux(flag, bmi); } |