1463d47f6SMacpaul Lin /* 2463d47f6SMacpaul Lin * Copyright (C) 2011 Andes Technology Corporation 3463d47f6SMacpaul Lin * Shawn Lin, Andes Technology Corporation <nobuhiro@andestech.com> 4463d47f6SMacpaul Lin * Macpaul Lin, Andes Technology Corporation <macpaul@andestech.com> 5463d47f6SMacpaul Lin * 6463d47f6SMacpaul Lin * This program is free software; you can redistribute it and/or modify 7463d47f6SMacpaul Lin * it under the terms of the GNU General Public License as published by 8463d47f6SMacpaul Lin * the Free Software Foundation; either version 2 of the License, or 9463d47f6SMacpaul Lin * (at your option) any later version. 10463d47f6SMacpaul Lin * 11463d47f6SMacpaul Lin * This program is distributed in the hope that it will be useful, 12463d47f6SMacpaul Lin * but WITHOUT ANY WARRANTY; without even the implied warranty of 13463d47f6SMacpaul Lin * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14463d47f6SMacpaul Lin * GNU General Public License for more details. 15463d47f6SMacpaul Lin * 16463d47f6SMacpaul Lin * You should have received a copy of the GNU General Public License 17463d47f6SMacpaul Lin * along with this program; if not, write to the Free Software 18463d47f6SMacpaul Lin * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19463d47f6SMacpaul Lin * 20463d47f6SMacpaul Lin */ 21463d47f6SMacpaul Lin 22463d47f6SMacpaul Lin #include <common.h> 23463d47f6SMacpaul Lin #include <command.h> 24463d47f6SMacpaul Lin #include <image.h> 25463d47f6SMacpaul Lin #include <u-boot/zlib.h> 26463d47f6SMacpaul Lin #include <asm/byteorder.h> 27463d47f6SMacpaul Lin 28463d47f6SMacpaul Lin DECLARE_GLOBAL_DATA_PTR; 29463d47f6SMacpaul Lin 30463d47f6SMacpaul Lin #if defined(CONFIG_SETUP_MEMORY_TAGS) || \ 31463d47f6SMacpaul Lin defined(CONFIG_CMDLINE_TAG) || \ 32463d47f6SMacpaul Lin defined(CONFIG_INITRD_TAG) || \ 33463d47f6SMacpaul Lin defined(CONFIG_SERIAL_TAG) || \ 34463d47f6SMacpaul Lin defined(CONFIG_REVISION_TAG) 35463d47f6SMacpaul Lin static void setup_start_tag(bd_t *bd); 36463d47f6SMacpaul Lin 37463d47f6SMacpaul Lin # ifdef CONFIG_SETUP_MEMORY_TAGS 38463d47f6SMacpaul Lin static void setup_memory_tags(bd_t *bd); 39463d47f6SMacpaul Lin # endif 40463d47f6SMacpaul Lin static void setup_commandline_tag(bd_t *bd, char *commandline); 41463d47f6SMacpaul Lin 42463d47f6SMacpaul Lin # ifdef CONFIG_INITRD_TAG 43463d47f6SMacpaul Lin static void setup_initrd_tag(bd_t *bd, ulong initrd_start, ulong initrd_end); 44463d47f6SMacpaul Lin # endif 45463d47f6SMacpaul Lin static void setup_end_tag(bd_t *bd); 46463d47f6SMacpaul Lin 47463d47f6SMacpaul Lin static struct tag *params; 48463d47f6SMacpaul Lin #endif /* CONFIG_SETUP_MEMORY_TAGS || CONFIG_CMDLINE_TAG || CONFIG_INITRD_TAG */ 49463d47f6SMacpaul Lin 50463d47f6SMacpaul Lin int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images) 51463d47f6SMacpaul Lin { 52463d47f6SMacpaul Lin bd_t *bd = gd->bd; 53463d47f6SMacpaul Lin char *s; 54463d47f6SMacpaul Lin int machid = bd->bi_arch_number; 55463d47f6SMacpaul Lin void (*theKernel)(int zero, int arch, uint params); 56463d47f6SMacpaul Lin 57463d47f6SMacpaul Lin #ifdef CONFIG_CMDLINE_TAG 58463d47f6SMacpaul Lin char *commandline = getenv("bootargs"); 59463d47f6SMacpaul Lin #endif 60463d47f6SMacpaul Lin 61*2cb0e55aSAndreas Bießmann /* 62*2cb0e55aSAndreas Bießmann * allow the PREP bootm subcommand, it is required for bootm to work 63*2cb0e55aSAndreas Bießmann */ 64*2cb0e55aSAndreas Bießmann if (flag & BOOTM_STATE_OS_PREP) 65*2cb0e55aSAndreas Bießmann return 0; 66*2cb0e55aSAndreas Bießmann 67463d47f6SMacpaul Lin if ((flag != 0) && (flag != BOOTM_STATE_OS_GO)) 68463d47f6SMacpaul Lin return 1; 69463d47f6SMacpaul Lin 70463d47f6SMacpaul Lin theKernel = (void (*)(int, int, uint))images->ep; 71463d47f6SMacpaul Lin 72463d47f6SMacpaul Lin s = getenv("machid"); 73463d47f6SMacpaul Lin if (s) { 74463d47f6SMacpaul Lin machid = simple_strtoul(s, NULL, 16); 75463d47f6SMacpaul Lin printf("Using machid 0x%x from environment\n", machid); 76463d47f6SMacpaul Lin } 77463d47f6SMacpaul Lin 78770605e4SSimon Glass bootstage_mark(BOOTSTAGE_ID_RUN_OS); 79463d47f6SMacpaul Lin 80463d47f6SMacpaul Lin debug("## Transferring control to Linux (at address %08lx) ...\n", 81463d47f6SMacpaul Lin (ulong)theKernel); 82463d47f6SMacpaul Lin 83463d47f6SMacpaul Lin #if defined(CONFIG_SETUP_MEMORY_TAGS) || \ 84463d47f6SMacpaul Lin defined(CONFIG_CMDLINE_TAG) || \ 85463d47f6SMacpaul Lin defined(CONFIG_INITRD_TAG) || \ 86463d47f6SMacpaul Lin defined(CONFIG_SERIAL_TAG) || \ 87463d47f6SMacpaul Lin defined(CONFIG_REVISION_TAG) 88463d47f6SMacpaul Lin setup_start_tag(bd); 89463d47f6SMacpaul Lin #ifdef CONFIG_SERIAL_TAG 90463d47f6SMacpaul Lin setup_serial_tag(¶ms); 91463d47f6SMacpaul Lin #endif 92463d47f6SMacpaul Lin #ifdef CONFIG_REVISION_TAG 93463d47f6SMacpaul Lin setup_revision_tag(¶ms); 94463d47f6SMacpaul Lin #endif 95463d47f6SMacpaul Lin #ifdef CONFIG_SETUP_MEMORY_TAGS 96463d47f6SMacpaul Lin setup_memory_tags(bd); 97463d47f6SMacpaul Lin #endif 98463d47f6SMacpaul Lin #ifdef CONFIG_CMDLINE_TAG 99463d47f6SMacpaul Lin setup_commandline_tag(bd, commandline); 100463d47f6SMacpaul Lin #endif 101463d47f6SMacpaul Lin #ifdef CONFIG_INITRD_TAG 102463d47f6SMacpaul Lin if (images->rd_start && images->rd_end) 103463d47f6SMacpaul Lin setup_initrd_tag(bd, images->rd_start, images->rd_end); 104463d47f6SMacpaul Lin #endif 105463d47f6SMacpaul Lin setup_end_tag(bd); 106463d47f6SMacpaul Lin #endif 107463d47f6SMacpaul Lin 108463d47f6SMacpaul Lin /* we assume that the kernel is in place */ 109463d47f6SMacpaul Lin printf("\nStarting kernel ...\n\n"); 110463d47f6SMacpaul Lin 111463d47f6SMacpaul Lin #ifdef CONFIG_USB_DEVICE 112463d47f6SMacpaul Lin { 113463d47f6SMacpaul Lin extern void udc_disconnect(void); 114463d47f6SMacpaul Lin udc_disconnect(); 115463d47f6SMacpaul Lin } 116463d47f6SMacpaul Lin #endif 117463d47f6SMacpaul Lin 118463d47f6SMacpaul Lin cleanup_before_linux(); 119463d47f6SMacpaul Lin 120463d47f6SMacpaul Lin theKernel(0, machid, bd->bi_boot_params); 121463d47f6SMacpaul Lin /* does not return */ 122463d47f6SMacpaul Lin 123463d47f6SMacpaul Lin return 1; 124463d47f6SMacpaul Lin } 125463d47f6SMacpaul Lin 126463d47f6SMacpaul Lin 127463d47f6SMacpaul Lin #if defined(CONFIG_SETUP_MEMORY_TAGS) || \ 128463d47f6SMacpaul Lin defined(CONFIG_CMDLINE_TAG) || \ 129463d47f6SMacpaul Lin defined(CONFIG_INITRD_TAG) || \ 130463d47f6SMacpaul Lin defined(CONFIG_SERIAL_TAG) || \ 131463d47f6SMacpaul Lin defined(CONFIG_REVISION_TAG) 132463d47f6SMacpaul Lin static void setup_start_tag(bd_t *bd) 133463d47f6SMacpaul Lin { 134463d47f6SMacpaul Lin params = (struct tag *)bd->bi_boot_params; 135463d47f6SMacpaul Lin 136463d47f6SMacpaul Lin params->hdr.tag = ATAG_CORE; 137463d47f6SMacpaul Lin params->hdr.size = tag_size(tag_core); 138463d47f6SMacpaul Lin 139463d47f6SMacpaul Lin params->u.core.flags = 0; 140463d47f6SMacpaul Lin params->u.core.pagesize = 0; 141463d47f6SMacpaul Lin params->u.core.rootdev = 0; 142463d47f6SMacpaul Lin 143463d47f6SMacpaul Lin params = tag_next(params); 144463d47f6SMacpaul Lin } 145463d47f6SMacpaul Lin 146463d47f6SMacpaul Lin 147463d47f6SMacpaul Lin #ifdef CONFIG_SETUP_MEMORY_TAGS 148463d47f6SMacpaul Lin static void setup_memory_tags(bd_t *bd) 149463d47f6SMacpaul Lin { 150463d47f6SMacpaul Lin int i; 151463d47f6SMacpaul Lin 152463d47f6SMacpaul Lin for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) { 153463d47f6SMacpaul Lin params->hdr.tag = ATAG_MEM; 154463d47f6SMacpaul Lin params->hdr.size = tag_size(tag_mem32); 155463d47f6SMacpaul Lin 156463d47f6SMacpaul Lin params->u.mem.start = bd->bi_dram[i].start; 157463d47f6SMacpaul Lin params->u.mem.size = bd->bi_dram[i].size; 158463d47f6SMacpaul Lin 159463d47f6SMacpaul Lin params = tag_next(params); 160463d47f6SMacpaul Lin } 161463d47f6SMacpaul Lin } 162463d47f6SMacpaul Lin #endif /* CONFIG_SETUP_MEMORY_TAGS */ 163463d47f6SMacpaul Lin 164463d47f6SMacpaul Lin 165463d47f6SMacpaul Lin static void setup_commandline_tag(bd_t *bd, char *commandline) 166463d47f6SMacpaul Lin { 167463d47f6SMacpaul Lin char *p; 168463d47f6SMacpaul Lin 169463d47f6SMacpaul Lin if (!commandline) 170463d47f6SMacpaul Lin return; 171463d47f6SMacpaul Lin 172463d47f6SMacpaul Lin /* eat leading white space */ 173463d47f6SMacpaul Lin for (p = commandline; *p == ' '; p++) 174463d47f6SMacpaul Lin ; 175463d47f6SMacpaul Lin 176463d47f6SMacpaul Lin /* skip non-existent command lines so the kernel will still 177463d47f6SMacpaul Lin * use its default command line. 178463d47f6SMacpaul Lin */ 179463d47f6SMacpaul Lin if (*p == '\0') 180463d47f6SMacpaul Lin return; 181463d47f6SMacpaul Lin 182463d47f6SMacpaul Lin params->hdr.tag = ATAG_CMDLINE; 183463d47f6SMacpaul Lin params->hdr.size = 184463d47f6SMacpaul Lin (sizeof(struct tag_header) + strlen(p) + 1 + 4) >> 2; 185463d47f6SMacpaul Lin 186463d47f6SMacpaul Lin strcpy(params->u.cmdline.cmdline, p) 187463d47f6SMacpaul Lin ; 188463d47f6SMacpaul Lin 189463d47f6SMacpaul Lin params = tag_next(params); 190463d47f6SMacpaul Lin } 191463d47f6SMacpaul Lin 192463d47f6SMacpaul Lin 193463d47f6SMacpaul Lin #ifdef CONFIG_INITRD_TAG 194463d47f6SMacpaul Lin static void setup_initrd_tag(bd_t *bd, ulong initrd_start, ulong initrd_end) 195463d47f6SMacpaul Lin { 196463d47f6SMacpaul Lin /* an ATAG_INITRD node tells the kernel where the compressed 197463d47f6SMacpaul Lin * ramdisk can be found. ATAG_RDIMG is a better name, actually. 198463d47f6SMacpaul Lin */ 199463d47f6SMacpaul Lin params->hdr.tag = ATAG_INITRD2; 200463d47f6SMacpaul Lin params->hdr.size = tag_size(tag_initrd); 201463d47f6SMacpaul Lin 202463d47f6SMacpaul Lin params->u.initrd.start = initrd_start; 203463d47f6SMacpaul Lin params->u.initrd.size = initrd_end - initrd_start; 204463d47f6SMacpaul Lin 205463d47f6SMacpaul Lin params = tag_next(params); 206463d47f6SMacpaul Lin } 207463d47f6SMacpaul Lin #endif /* CONFIG_INITRD_TAG */ 208463d47f6SMacpaul Lin 209463d47f6SMacpaul Lin #ifdef CONFIG_SERIAL_TAG 210463d47f6SMacpaul Lin void setup_serial_tag(struct tag **tmp) 211463d47f6SMacpaul Lin { 212463d47f6SMacpaul Lin struct tag *params = *tmp; 213463d47f6SMacpaul Lin struct tag_serialnr serialnr; 214463d47f6SMacpaul Lin void get_board_serial(struct tag_serialnr *serialnr); 215463d47f6SMacpaul Lin 216463d47f6SMacpaul Lin get_board_serial(&serialnr); 217463d47f6SMacpaul Lin params->hdr.tag = ATAG_SERIAL; 218463d47f6SMacpaul Lin params->hdr.size = tag_size(tag_serialnr); 219463d47f6SMacpaul Lin params->u.serialnr.low = serialnr.low; 220463d47f6SMacpaul Lin params->u.serialnr.high = serialnr.high; 221463d47f6SMacpaul Lin params = tag_next(params); 222463d47f6SMacpaul Lin *tmp = params; 223463d47f6SMacpaul Lin } 224463d47f6SMacpaul Lin #endif 225463d47f6SMacpaul Lin 226463d47f6SMacpaul Lin #ifdef CONFIG_REVISION_TAG 227463d47f6SMacpaul Lin void setup_revision_tag(struct tag **in_params) 228463d47f6SMacpaul Lin { 229463d47f6SMacpaul Lin u32 rev = 0; 230463d47f6SMacpaul Lin u32 get_board_rev(void); 231463d47f6SMacpaul Lin 232463d47f6SMacpaul Lin rev = get_board_rev(); 233463d47f6SMacpaul Lin params->hdr.tag = ATAG_REVISION; 234463d47f6SMacpaul Lin params->hdr.size = tag_size(tag_revision); 235463d47f6SMacpaul Lin params->u.revision.rev = rev; 236463d47f6SMacpaul Lin params = tag_next(params); 237463d47f6SMacpaul Lin } 238463d47f6SMacpaul Lin #endif /* CONFIG_REVISION_TAG */ 239463d47f6SMacpaul Lin 240463d47f6SMacpaul Lin 241463d47f6SMacpaul Lin static void setup_end_tag(bd_t *bd) 242463d47f6SMacpaul Lin { 243463d47f6SMacpaul Lin params->hdr.tag = ATAG_NONE; 244463d47f6SMacpaul Lin params->hdr.size = 0; 245463d47f6SMacpaul Lin } 246463d47f6SMacpaul Lin 247463d47f6SMacpaul Lin #endif /* CONFIG_SETUP_MEMORY_TAGS || CONFIG_CMDLINE_TAG || CONFIG_INITRD_TAG */ 248