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