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 * 61a459660SWolfgang Denk * SPDX-License-Identifier: GPL-2.0+ 7463d47f6SMacpaul Lin */ 8463d47f6SMacpaul Lin 9463d47f6SMacpaul Lin #include <common.h> 10463d47f6SMacpaul Lin #include <command.h> 11463d47f6SMacpaul Lin #include <image.h> 12463d47f6SMacpaul Lin #include <u-boot/zlib.h> 13463d47f6SMacpaul Lin #include <asm/byteorder.h> 14b841b6e9Srick #include <asm/bootm.h> 15*3a53e99cSSimon Glass #include <asm/setup.h> 16463d47f6SMacpaul Lin 17463d47f6SMacpaul Lin DECLARE_GLOBAL_DATA_PTR; 18463d47f6SMacpaul Lin 1986132af7Srick int arch_fixup_fdt(void *blob) 2086132af7Srick { 2186132af7Srick return 0; 2286132af7Srick } 2386132af7Srick 2486132af7Srick 25463d47f6SMacpaul Lin #if defined(CONFIG_SETUP_MEMORY_TAGS) || \ 26463d47f6SMacpaul Lin defined(CONFIG_CMDLINE_TAG) || \ 27463d47f6SMacpaul Lin defined(CONFIG_INITRD_TAG) || \ 28463d47f6SMacpaul Lin defined(CONFIG_SERIAL_TAG) || \ 29463d47f6SMacpaul Lin defined(CONFIG_REVISION_TAG) 30463d47f6SMacpaul Lin static void setup_start_tag(bd_t *bd); 31463d47f6SMacpaul Lin 32463d47f6SMacpaul Lin # ifdef CONFIG_SETUP_MEMORY_TAGS 33463d47f6SMacpaul Lin static void setup_memory_tags(bd_t *bd); 34463d47f6SMacpaul Lin # endif 35463d47f6SMacpaul Lin static void setup_commandline_tag(bd_t *bd, char *commandline); 36463d47f6SMacpaul Lin 37463d47f6SMacpaul Lin # ifdef CONFIG_INITRD_TAG 38463d47f6SMacpaul Lin static void setup_initrd_tag(bd_t *bd, ulong initrd_start, ulong initrd_end); 39463d47f6SMacpaul Lin # endif 40463d47f6SMacpaul Lin static void setup_end_tag(bd_t *bd); 41463d47f6SMacpaul Lin 42463d47f6SMacpaul Lin static struct tag *params; 43463d47f6SMacpaul Lin #endif /* CONFIG_SETUP_MEMORY_TAGS || CONFIG_CMDLINE_TAG || CONFIG_INITRD_TAG */ 44463d47f6SMacpaul Lin 45463d47f6SMacpaul Lin int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images) 46463d47f6SMacpaul Lin { 47463d47f6SMacpaul Lin bd_t *bd = gd->bd; 48463d47f6SMacpaul Lin char *s; 49463d47f6SMacpaul Lin int machid = bd->bi_arch_number; 50463d47f6SMacpaul Lin void (*theKernel)(int zero, int arch, uint params); 51463d47f6SMacpaul Lin 52463d47f6SMacpaul Lin #ifdef CONFIG_CMDLINE_TAG 53463d47f6SMacpaul Lin char *commandline = getenv("bootargs"); 54463d47f6SMacpaul Lin #endif 55463d47f6SMacpaul Lin 562cb0e55aSAndreas Bießmann /* 572cb0e55aSAndreas Bießmann * allow the PREP bootm subcommand, it is required for bootm to work 582cb0e55aSAndreas Bießmann */ 592cb0e55aSAndreas Bießmann if (flag & BOOTM_STATE_OS_PREP) 602cb0e55aSAndreas Bießmann return 0; 612cb0e55aSAndreas Bießmann 62463d47f6SMacpaul Lin if ((flag != 0) && (flag != BOOTM_STATE_OS_GO)) 63463d47f6SMacpaul Lin return 1; 64463d47f6SMacpaul Lin 65463d47f6SMacpaul Lin theKernel = (void (*)(int, int, uint))images->ep; 66463d47f6SMacpaul Lin 67463d47f6SMacpaul Lin s = getenv("machid"); 68463d47f6SMacpaul Lin if (s) { 69463d47f6SMacpaul Lin machid = simple_strtoul(s, NULL, 16); 70463d47f6SMacpaul Lin printf("Using machid 0x%x from environment\n", machid); 71463d47f6SMacpaul Lin } 72463d47f6SMacpaul Lin 73770605e4SSimon Glass bootstage_mark(BOOTSTAGE_ID_RUN_OS); 74463d47f6SMacpaul Lin 75463d47f6SMacpaul Lin debug("## Transferring control to Linux (at address %08lx) ...\n", 76463d47f6SMacpaul Lin (ulong)theKernel); 77463d47f6SMacpaul Lin 78b841b6e9Srick if (IMAGE_ENABLE_OF_LIBFDT && images->ft_len) { 79b841b6e9Srick #ifdef CONFIG_OF_LIBFDT 80b841b6e9Srick debug("using: FDT\n"); 81b841b6e9Srick if (image_setup_linux(images)) { 82b841b6e9Srick printf("FDT creation failed! hanging..."); 83b841b6e9Srick hang(); 84b841b6e9Srick } 85b841b6e9Srick #endif 86b841b6e9Srick } else if (BOOTM_ENABLE_TAGS) { 87463d47f6SMacpaul Lin #if defined(CONFIG_SETUP_MEMORY_TAGS) || \ 88463d47f6SMacpaul Lin defined(CONFIG_CMDLINE_TAG) || \ 89463d47f6SMacpaul Lin defined(CONFIG_INITRD_TAG) || \ 90463d47f6SMacpaul Lin defined(CONFIG_SERIAL_TAG) || \ 91463d47f6SMacpaul Lin defined(CONFIG_REVISION_TAG) 92463d47f6SMacpaul Lin setup_start_tag(bd); 93463d47f6SMacpaul Lin #ifdef CONFIG_SERIAL_TAG 94463d47f6SMacpaul Lin setup_serial_tag(¶ms); 95463d47f6SMacpaul Lin #endif 96463d47f6SMacpaul Lin #ifdef CONFIG_REVISION_TAG 97463d47f6SMacpaul Lin setup_revision_tag(¶ms); 98463d47f6SMacpaul Lin #endif 99463d47f6SMacpaul Lin #ifdef CONFIG_SETUP_MEMORY_TAGS 100463d47f6SMacpaul Lin setup_memory_tags(bd); 101463d47f6SMacpaul Lin #endif 102463d47f6SMacpaul Lin #ifdef CONFIG_CMDLINE_TAG 103463d47f6SMacpaul Lin setup_commandline_tag(bd, commandline); 104463d47f6SMacpaul Lin #endif 105463d47f6SMacpaul Lin #ifdef CONFIG_INITRD_TAG 106463d47f6SMacpaul Lin if (images->rd_start && images->rd_end) 107463d47f6SMacpaul Lin setup_initrd_tag(bd, images->rd_start, images->rd_end); 108463d47f6SMacpaul Lin #endif 109463d47f6SMacpaul Lin setup_end_tag(bd); 110463d47f6SMacpaul Lin #endif 111463d47f6SMacpaul Lin 112463d47f6SMacpaul Lin /* we assume that the kernel is in place */ 113463d47f6SMacpaul Lin printf("\nStarting kernel ...\n\n"); 114463d47f6SMacpaul Lin 115463d47f6SMacpaul Lin #ifdef CONFIG_USB_DEVICE 116463d47f6SMacpaul Lin { 117463d47f6SMacpaul Lin extern void udc_disconnect(void); 118463d47f6SMacpaul Lin udc_disconnect(); 119463d47f6SMacpaul Lin } 120463d47f6SMacpaul Lin #endif 121b841b6e9Srick } 122463d47f6SMacpaul Lin cleanup_before_linux(); 123b841b6e9Srick if (IMAGE_ENABLE_OF_LIBFDT && images->ft_len) 124b841b6e9Srick theKernel(0, machid, (unsigned long)images->ft_addr); 125b841b6e9Srick else 126463d47f6SMacpaul Lin theKernel(0, machid, bd->bi_boot_params); 127463d47f6SMacpaul Lin /* does not return */ 128463d47f6SMacpaul Lin 129463d47f6SMacpaul Lin return 1; 130463d47f6SMacpaul Lin } 131463d47f6SMacpaul Lin 132463d47f6SMacpaul Lin #if defined(CONFIG_SETUP_MEMORY_TAGS) || \ 133463d47f6SMacpaul Lin defined(CONFIG_CMDLINE_TAG) || \ 134463d47f6SMacpaul Lin defined(CONFIG_INITRD_TAG) || \ 135463d47f6SMacpaul Lin defined(CONFIG_SERIAL_TAG) || \ 136463d47f6SMacpaul Lin defined(CONFIG_REVISION_TAG) 137463d47f6SMacpaul Lin static void setup_start_tag(bd_t *bd) 138463d47f6SMacpaul Lin { 139463d47f6SMacpaul Lin params = (struct tag *)bd->bi_boot_params; 140463d47f6SMacpaul Lin 141463d47f6SMacpaul Lin params->hdr.tag = ATAG_CORE; 142463d47f6SMacpaul Lin params->hdr.size = tag_size(tag_core); 143463d47f6SMacpaul Lin 144463d47f6SMacpaul Lin params->u.core.flags = 0; 145463d47f6SMacpaul Lin params->u.core.pagesize = 0; 146463d47f6SMacpaul Lin params->u.core.rootdev = 0; 147463d47f6SMacpaul Lin 148463d47f6SMacpaul Lin params = tag_next(params); 149463d47f6SMacpaul Lin } 150463d47f6SMacpaul Lin 151463d47f6SMacpaul Lin #ifdef CONFIG_SETUP_MEMORY_TAGS 152463d47f6SMacpaul Lin static void setup_memory_tags(bd_t *bd) 153463d47f6SMacpaul Lin { 154463d47f6SMacpaul Lin int i; 155463d47f6SMacpaul Lin 156463d47f6SMacpaul Lin for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) { 157463d47f6SMacpaul Lin params->hdr.tag = ATAG_MEM; 158463d47f6SMacpaul Lin params->hdr.size = tag_size(tag_mem32); 159463d47f6SMacpaul Lin 160463d47f6SMacpaul Lin params->u.mem.start = bd->bi_dram[i].start; 161463d47f6SMacpaul Lin params->u.mem.size = bd->bi_dram[i].size; 162463d47f6SMacpaul Lin 163463d47f6SMacpaul Lin params = tag_next(params); 164463d47f6SMacpaul Lin } 165463d47f6SMacpaul Lin } 166463d47f6SMacpaul Lin #endif /* CONFIG_SETUP_MEMORY_TAGS */ 167463d47f6SMacpaul Lin 168463d47f6SMacpaul Lin static void setup_commandline_tag(bd_t *bd, char *commandline) 169463d47f6SMacpaul Lin { 170463d47f6SMacpaul Lin char *p; 171463d47f6SMacpaul Lin 172463d47f6SMacpaul Lin if (!commandline) 173463d47f6SMacpaul Lin return; 174463d47f6SMacpaul Lin 175463d47f6SMacpaul Lin /* eat leading white space */ 176463d47f6SMacpaul Lin for (p = commandline; *p == ' '; p++) 177463d47f6SMacpaul Lin ; 178463d47f6SMacpaul Lin 179463d47f6SMacpaul Lin /* skip non-existent command lines so the kernel will still 180463d47f6SMacpaul Lin * use its default command line. 181463d47f6SMacpaul Lin */ 182463d47f6SMacpaul Lin if (*p == '\0') 183463d47f6SMacpaul Lin return; 184463d47f6SMacpaul Lin 185463d47f6SMacpaul Lin params->hdr.tag = ATAG_CMDLINE; 186463d47f6SMacpaul Lin params->hdr.size = 187463d47f6SMacpaul Lin (sizeof(struct tag_header) + strlen(p) + 1 + 4) >> 2; 188463d47f6SMacpaul Lin 189463d47f6SMacpaul Lin strcpy(params->u.cmdline.cmdline, p) 190463d47f6SMacpaul Lin ; 191463d47f6SMacpaul Lin 192463d47f6SMacpaul Lin params = tag_next(params); 193463d47f6SMacpaul Lin } 194463d47f6SMacpaul Lin 195463d47f6SMacpaul Lin #ifdef CONFIG_INITRD_TAG 196463d47f6SMacpaul Lin static void setup_initrd_tag(bd_t *bd, ulong initrd_start, ulong initrd_end) 197463d47f6SMacpaul Lin { 198463d47f6SMacpaul Lin /* an ATAG_INITRD node tells the kernel where the compressed 199463d47f6SMacpaul Lin * ramdisk can be found. ATAG_RDIMG is a better name, actually. 200463d47f6SMacpaul Lin */ 201463d47f6SMacpaul Lin params->hdr.tag = ATAG_INITRD2; 202463d47f6SMacpaul Lin params->hdr.size = tag_size(tag_initrd); 203463d47f6SMacpaul Lin 204463d47f6SMacpaul Lin params->u.initrd.start = initrd_start; 205463d47f6SMacpaul Lin params->u.initrd.size = initrd_end - initrd_start; 206463d47f6SMacpaul Lin 207463d47f6SMacpaul Lin params = tag_next(params); 208463d47f6SMacpaul Lin } 209463d47f6SMacpaul Lin #endif /* CONFIG_INITRD_TAG */ 210463d47f6SMacpaul Lin 211463d47f6SMacpaul Lin #ifdef CONFIG_SERIAL_TAG 212463d47f6SMacpaul Lin void setup_serial_tag(struct tag **tmp) 213463d47f6SMacpaul Lin { 214463d47f6SMacpaul Lin struct tag *params = *tmp; 215463d47f6SMacpaul Lin struct tag_serialnr serialnr; 216463d47f6SMacpaul Lin void get_board_serial(struct tag_serialnr *serialnr); 217463d47f6SMacpaul Lin 218463d47f6SMacpaul Lin get_board_serial(&serialnr); 219463d47f6SMacpaul Lin params->hdr.tag = ATAG_SERIAL; 220463d47f6SMacpaul Lin params->hdr.size = tag_size(tag_serialnr); 221463d47f6SMacpaul Lin params->u.serialnr.low = serialnr.low; 222463d47f6SMacpaul Lin params->u.serialnr.high = serialnr.high; 223463d47f6SMacpaul Lin params = tag_next(params); 224463d47f6SMacpaul Lin *tmp = params; 225463d47f6SMacpaul Lin } 226463d47f6SMacpaul Lin #endif 227463d47f6SMacpaul Lin 228463d47f6SMacpaul Lin #ifdef CONFIG_REVISION_TAG 229463d47f6SMacpaul Lin void setup_revision_tag(struct tag **in_params) 230463d47f6SMacpaul Lin { 231463d47f6SMacpaul Lin u32 rev = 0; 232463d47f6SMacpaul Lin u32 get_board_rev(void); 233463d47f6SMacpaul Lin 234463d47f6SMacpaul Lin rev = get_board_rev(); 235463d47f6SMacpaul Lin params->hdr.tag = ATAG_REVISION; 236463d47f6SMacpaul Lin params->hdr.size = tag_size(tag_revision); 237463d47f6SMacpaul Lin params->u.revision.rev = rev; 238463d47f6SMacpaul Lin params = tag_next(params); 239463d47f6SMacpaul Lin } 240463d47f6SMacpaul Lin #endif /* CONFIG_REVISION_TAG */ 241463d47f6SMacpaul Lin 242463d47f6SMacpaul Lin static void setup_end_tag(bd_t *bd) 243463d47f6SMacpaul Lin { 244463d47f6SMacpaul Lin params->hdr.tag = ATAG_NONE; 245463d47f6SMacpaul Lin params->hdr.size = 0; 246463d47f6SMacpaul Lin } 247463d47f6SMacpaul Lin 248463d47f6SMacpaul Lin #endif /* CONFIG_SETUP_MEMORY_TAGS || CONFIG_CMDLINE_TAG || CONFIG_INITRD_TAG */ 249