1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Copyright (C) 2011 Andes Technology Corporation 4 * Shawn Lin, Andes Technology Corporation <nobuhiro@andestech.com> 5 * Macpaul Lin, Andes Technology Corporation <macpaul@andestech.com> 6 * Rick Chen, Andes Technology Corporation <rick@andestech.com> 7 */ 8 9#include <bootstage.h> 10#include <bootm.h> 11#include <command.h> 12#include <dm.h> 13#include <fdt_support.h> 14#include <hang.h> 15#include <log.h> 16#include <asm/global_data.h> 17#include <dm/root.h> 18#include <image.h> 19#include <asm/byteorder.h> 20#include <asm/csr.h> 21#include <asm/smp.h> 22#include <dm/device.h> 23#include <dm/root.h> 24#include <u-boot/zlib.h> 25 26DECLARE_GLOBAL_DATA_PTR; 27 28__weak void board_quiesce_devices(void) 29{ 30} 31 32/** 33 * announce_and_cleanup() - Print message and prepare for kernel boot 34 * 35 * @fake: non-zero to do everything except actually boot 36 */ 37static void announce_and_cleanup(int fake) 38{ 39 printf("\nStarting kernel ...%s\n\n", fake ? 40 "(fake run for tracing)" : ""); 41 bootstage_mark_name(BOOTSTAGE_ID_BOOTM_HANDOFF, "start_kernel"); 42#ifdef CONFIG_BOOTSTAGE_FDT 43 bootstage_fdt_add_report(); 44#endif 45#if CONFIG_IS_ENABLED(BOOTSTAGE_REPORT) 46 bootstage_report(); 47#endif 48 49#ifdef CONFIG_USB_DEVICE 50 udc_disconnect(); 51#endif 52 53 board_quiesce_devices(); 54 55 /* 56 * Call remove function of all devices with a removal flag set. 57 * This may be useful for last-stage operations, like cancelling 58 * of DMA operation or releasing device internal buffers. 59 */ 60 dm_remove_devices_flags(DM_REMOVE_ACTIVE_ALL); 61 62 cleanup_before_linux(); 63} 64 65static void boot_prep_linux(struct bootm_headers *images) 66{ 67 if (CONFIG_IS_ENABLED(OF_LIBFDT) && IS_ENABLED(CONFIG_LMB) && images->ft_len) { 68 debug("using: FDT\n"); 69 if (image_setup_linux(images)) { 70 printf("FDT creation failed! hanging..."); 71 hang(); 72 } 73 } else { 74 printf("Device tree not found or missing FDT support\n"); 75 hang(); 76 } 77} 78 79static void boot_jump_linux(struct bootm_headers *images, int flag) 80{ 81 void (*kernel)(ulong hart, void *dtb); 82 int fake = (flag & BOOTM_STATE_OS_FAKE_GO); 83#ifdef CONFIG_SMP 84 int ret; 85#endif 86 87 kernel = (void (*)(ulong, void *))images->ep; 88 89 bootstage_mark(BOOTSTAGE_ID_RUN_OS); 90 91 debug("## Transferring control to kernel (at address %08lx) ...\n", 92 (ulong)kernel); 93 94 announce_and_cleanup(fake); 95 96 if (!fake) { 97 if (CONFIG_IS_ENABLED(OF_LIBFDT) && images->ft_len) { 98#ifdef CONFIG_SMP 99 ret = smp_call_function(images->ep, 100 (ulong)images->ft_addr, 0, 0); 101 if (ret) 102 hang(); 103#endif 104 kernel(gd->arch.boot_hart, images->ft_addr); 105 } 106 } 107} 108 109int do_bootm_linux(int flag, struct bootm_info *bmi) 110{ 111 struct bootm_headers *images = bmi->images; 112 113 /* No need for those on RISC-V */ 114 if (flag & BOOTM_STATE_OS_BD_T || flag & BOOTM_STATE_OS_CMDLINE) 115 return -1; 116 117 if (flag & BOOTM_STATE_OS_PREP) { 118 boot_prep_linux(images); 119 return 0; 120 } 121 122 if (flag & (BOOTM_STATE_OS_GO | BOOTM_STATE_OS_FAKE_GO)) { 123 boot_jump_linux(images, flag); 124 return 0; 125 } 126 127 boot_prep_linux(images); 128 boot_jump_linux(images, flag); 129 return 0; 130} 131 132int do_bootm_vxworks(int flag, struct bootm_info *bmi) 133{ 134 return do_bootm_linux(flag, bmi); 135} 136 137static ulong get_sp(void) 138{ 139 ulong ret; 140 141 asm("mv %0, sp" : "=r"(ret) : ); 142 return ret; 143} 144 145void arch_lmb_reserve(struct lmb *lmb) 146{ 147 arch_lmb_reserve_generic(lmb, get_sp(), gd->ram_top, 4096); 148} 149