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