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