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 <common.h> 10 #include <command.h> 11 #include <dm.h> 12 #include <dm/root.h> 13 #include <image.h> 14 #include <asm/byteorder.h> 15 #include <asm/csr.h> 16 #include <dm/device.h> 17 #include <dm/root.h> 18 #include <u-boot/zlib.h> 19 20 DECLARE_GLOBAL_DATA_PTR; 21 22 __weak void board_quiesce_devices(void) 23 { 24 } 25 26 int arch_fixup_fdt(void *blob) 27 { 28 return 0; 29 } 30 31 /** 32 * announce_and_cleanup() - Print message and prepare for kernel boot 33 * 34 * @fake: non-zero to do everything except actually boot 35 */ 36 static void announce_and_cleanup(int fake) 37 { 38 printf("\nStarting kernel ...%s\n\n", fake ? 39 "(fake run for tracing)" : ""); 40 bootstage_mark_name(BOOTSTAGE_ID_BOOTM_HANDOFF, "start_kernel"); 41 #ifdef CONFIG_BOOTSTAGE_FDT 42 bootstage_fdt_add_report(); 43 #endif 44 #ifdef CONFIG_BOOTSTAGE_REPORT 45 bootstage_report(); 46 #endif 47 48 #ifdef CONFIG_USB_DEVICE 49 udc_disconnect(); 50 #endif 51 52 board_quiesce_devices(); 53 54 /* 55 * Call remove function of all devices with a removal flag set. 56 * This may be useful for last-stage operations, like cancelling 57 * of DMA operation or releasing device internal buffers. 58 */ 59 dm_remove_devices_flags(DM_REMOVE_ACTIVE_ALL); 60 61 cleanup_before_linux(); 62 } 63 64 static void boot_prep_linux(bootm_headers_t *images) 65 { 66 if (IMAGE_ENABLE_OF_LIBFDT && images->ft_len) { 67 #ifdef CONFIG_OF_LIBFDT 68 debug("using: FDT\n"); 69 if (image_setup_linux(images)) { 70 printf("FDT creation failed! hanging..."); 71 hang(); 72 } 73 #endif 74 } else { 75 printf("Device tree not found or missing FDT support\n"); 76 hang(); 77 } 78 } 79 80 static void boot_jump_linux(bootm_headers_t *images, int flag) 81 { 82 void (*kernel)(ulong hart, void *dtb); 83 int fake = (flag & BOOTM_STATE_OS_FAKE_GO); 84 85 kernel = (void (*)(ulong, void *))images->ep; 86 87 bootstage_mark(BOOTSTAGE_ID_RUN_OS); 88 89 debug("## Transferring control to Linux (at address %08lx) ...\n", 90 (ulong)kernel); 91 92 announce_and_cleanup(fake); 93 94 if (!fake) { 95 if (IMAGE_ENABLE_OF_LIBFDT && images->ft_len) 96 kernel(csr_read(mhartid), images->ft_addr); 97 } 98 } 99 100 int do_bootm_linux(int flag, int argc, char * const argv[], 101 bootm_headers_t *images) 102 { 103 /* No need for those on RISC-V */ 104 if (flag & BOOTM_STATE_OS_BD_T || flag & BOOTM_STATE_OS_CMDLINE) 105 return -1; 106 107 if (flag & BOOTM_STATE_OS_PREP) { 108 boot_prep_linux(images); 109 return 0; 110 } 111 112 if (flag & (BOOTM_STATE_OS_GO | BOOTM_STATE_OS_FAKE_GO)) { 113 boot_jump_linux(images, flag); 114 return 0; 115 } 116 117 boot_prep_linux(images); 118 boot_jump_linux(images, flag); 119 return 0; 120 } 121