1 /* 2 * Copyright (C) 2011 Andes Technology Corporation 3 * Shawn Lin, Andes Technology Corporation <nobuhiro@andestech.com> 4 * Macpaul Lin, Andes Technology Corporation <macpaul@andestech.com> 5 * 6 * SPDX-License-Identifier: GPL-2.0+ 7 */ 8 9 #include <common.h> 10 #include <command.h> 11 #include <image.h> 12 #include <u-boot/zlib.h> 13 #include <asm/byteorder.h> 14 #include <asm/bootm.h> 15 16 DECLARE_GLOBAL_DATA_PTR; 17 18 int arch_fixup_fdt(void *blob) 19 { 20 return 0; 21 } 22 23 24 #if defined(CONFIG_SETUP_MEMORY_TAGS) || \ 25 defined(CONFIG_CMDLINE_TAG) || \ 26 defined(CONFIG_INITRD_TAG) || \ 27 defined(CONFIG_SERIAL_TAG) || \ 28 defined(CONFIG_REVISION_TAG) 29 static void setup_start_tag(bd_t *bd); 30 31 # ifdef CONFIG_SETUP_MEMORY_TAGS 32 static void setup_memory_tags(bd_t *bd); 33 # endif 34 static void setup_commandline_tag(bd_t *bd, char *commandline); 35 36 # ifdef CONFIG_INITRD_TAG 37 static void setup_initrd_tag(bd_t *bd, ulong initrd_start, ulong initrd_end); 38 # endif 39 static void setup_end_tag(bd_t *bd); 40 41 static struct tag *params; 42 #endif /* CONFIG_SETUP_MEMORY_TAGS || CONFIG_CMDLINE_TAG || CONFIG_INITRD_TAG */ 43 44 int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images) 45 { 46 bd_t *bd = gd->bd; 47 char *s; 48 int machid = bd->bi_arch_number; 49 void (*theKernel)(int zero, int arch, uint params); 50 51 #ifdef CONFIG_CMDLINE_TAG 52 char *commandline = getenv("bootargs"); 53 #endif 54 55 /* 56 * allow the PREP bootm subcommand, it is required for bootm to work 57 */ 58 if (flag & BOOTM_STATE_OS_PREP) 59 return 0; 60 61 if ((flag != 0) && (flag != BOOTM_STATE_OS_GO)) 62 return 1; 63 64 theKernel = (void (*)(int, int, uint))images->ep; 65 66 s = getenv("machid"); 67 if (s) { 68 machid = simple_strtoul(s, NULL, 16); 69 printf("Using machid 0x%x from environment\n", machid); 70 } 71 72 bootstage_mark(BOOTSTAGE_ID_RUN_OS); 73 74 debug("## Transferring control to Linux (at address %08lx) ...\n", 75 (ulong)theKernel); 76 77 if (IMAGE_ENABLE_OF_LIBFDT && images->ft_len) { 78 #ifdef CONFIG_OF_LIBFDT 79 debug("using: FDT\n"); 80 if (image_setup_linux(images)) { 81 printf("FDT creation failed! hanging..."); 82 hang(); 83 } 84 #endif 85 } else if (BOOTM_ENABLE_TAGS) { 86 #if defined(CONFIG_SETUP_MEMORY_TAGS) || \ 87 defined(CONFIG_CMDLINE_TAG) || \ 88 defined(CONFIG_INITRD_TAG) || \ 89 defined(CONFIG_SERIAL_TAG) || \ 90 defined(CONFIG_REVISION_TAG) 91 setup_start_tag(bd); 92 #ifdef CONFIG_SERIAL_TAG 93 setup_serial_tag(¶ms); 94 #endif 95 #ifdef CONFIG_REVISION_TAG 96 setup_revision_tag(¶ms); 97 #endif 98 #ifdef CONFIG_SETUP_MEMORY_TAGS 99 setup_memory_tags(bd); 100 #endif 101 #ifdef CONFIG_CMDLINE_TAG 102 setup_commandline_tag(bd, commandline); 103 #endif 104 #ifdef CONFIG_INITRD_TAG 105 if (images->rd_start && images->rd_end) 106 setup_initrd_tag(bd, images->rd_start, images->rd_end); 107 #endif 108 setup_end_tag(bd); 109 #endif 110 111 /* we assume that the kernel is in place */ 112 printf("\nStarting kernel ...\n\n"); 113 114 #ifdef CONFIG_USB_DEVICE 115 { 116 extern void udc_disconnect(void); 117 udc_disconnect(); 118 } 119 #endif 120 } 121 cleanup_before_linux(); 122 if (IMAGE_ENABLE_OF_LIBFDT && images->ft_len) 123 theKernel(0, machid, (unsigned long)images->ft_addr); 124 else 125 theKernel(0, machid, bd->bi_boot_params); 126 /* does not return */ 127 128 return 1; 129 } 130 131 #if defined(CONFIG_SETUP_MEMORY_TAGS) || \ 132 defined(CONFIG_CMDLINE_TAG) || \ 133 defined(CONFIG_INITRD_TAG) || \ 134 defined(CONFIG_SERIAL_TAG) || \ 135 defined(CONFIG_REVISION_TAG) 136 static void setup_start_tag(bd_t *bd) 137 { 138 params = (struct tag *)bd->bi_boot_params; 139 140 params->hdr.tag = ATAG_CORE; 141 params->hdr.size = tag_size(tag_core); 142 143 params->u.core.flags = 0; 144 params->u.core.pagesize = 0; 145 params->u.core.rootdev = 0; 146 147 params = tag_next(params); 148 } 149 150 #ifdef CONFIG_SETUP_MEMORY_TAGS 151 static void setup_memory_tags(bd_t *bd) 152 { 153 int i; 154 155 for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) { 156 params->hdr.tag = ATAG_MEM; 157 params->hdr.size = tag_size(tag_mem32); 158 159 params->u.mem.start = bd->bi_dram[i].start; 160 params->u.mem.size = bd->bi_dram[i].size; 161 162 params = tag_next(params); 163 } 164 } 165 #endif /* CONFIG_SETUP_MEMORY_TAGS */ 166 167 static void setup_commandline_tag(bd_t *bd, char *commandline) 168 { 169 char *p; 170 171 if (!commandline) 172 return; 173 174 /* eat leading white space */ 175 for (p = commandline; *p == ' '; p++) 176 ; 177 178 /* skip non-existent command lines so the kernel will still 179 * use its default command line. 180 */ 181 if (*p == '\0') 182 return; 183 184 params->hdr.tag = ATAG_CMDLINE; 185 params->hdr.size = 186 (sizeof(struct tag_header) + strlen(p) + 1 + 4) >> 2; 187 188 strcpy(params->u.cmdline.cmdline, p) 189 ; 190 191 params = tag_next(params); 192 } 193 194 #ifdef CONFIG_INITRD_TAG 195 static void setup_initrd_tag(bd_t *bd, ulong initrd_start, ulong initrd_end) 196 { 197 /* an ATAG_INITRD node tells the kernel where the compressed 198 * ramdisk can be found. ATAG_RDIMG is a better name, actually. 199 */ 200 params->hdr.tag = ATAG_INITRD2; 201 params->hdr.size = tag_size(tag_initrd); 202 203 params->u.initrd.start = initrd_start; 204 params->u.initrd.size = initrd_end - initrd_start; 205 206 params = tag_next(params); 207 } 208 #endif /* CONFIG_INITRD_TAG */ 209 210 #ifdef CONFIG_SERIAL_TAG 211 void setup_serial_tag(struct tag **tmp) 212 { 213 struct tag *params = *tmp; 214 struct tag_serialnr serialnr; 215 void get_board_serial(struct tag_serialnr *serialnr); 216 217 get_board_serial(&serialnr); 218 params->hdr.tag = ATAG_SERIAL; 219 params->hdr.size = tag_size(tag_serialnr); 220 params->u.serialnr.low = serialnr.low; 221 params->u.serialnr.high = serialnr.high; 222 params = tag_next(params); 223 *tmp = params; 224 } 225 #endif 226 227 #ifdef CONFIG_REVISION_TAG 228 void setup_revision_tag(struct tag **in_params) 229 { 230 u32 rev = 0; 231 u32 get_board_rev(void); 232 233 rev = get_board_rev(); 234 params->hdr.tag = ATAG_REVISION; 235 params->hdr.size = tag_size(tag_revision); 236 params->u.revision.rev = rev; 237 params = tag_next(params); 238 } 239 #endif /* CONFIG_REVISION_TAG */ 240 241 static void setup_end_tag(bd_t *bd) 242 { 243 params->hdr.tag = ATAG_NONE; 244 params->hdr.size = 0; 245 } 246 247 #endif /* CONFIG_SETUP_MEMORY_TAGS || CONFIG_CMDLINE_TAG || CONFIG_INITRD_TAG */ 248