1*463d47f6SMacpaul Lin /* 2*463d47f6SMacpaul Lin * Copyright (C) 2011 Andes Technology Corporation 3*463d47f6SMacpaul Lin * Shawn Lin, Andes Technology Corporation <nobuhiro@andestech.com> 4*463d47f6SMacpaul Lin * Macpaul Lin, Andes Technology Corporation <macpaul@andestech.com> 5*463d47f6SMacpaul Lin * 6*463d47f6SMacpaul Lin * This program is free software; you can redistribute it and/or modify 7*463d47f6SMacpaul Lin * it under the terms of the GNU General Public License as published by 8*463d47f6SMacpaul Lin * the Free Software Foundation; either version 2 of the License, or 9*463d47f6SMacpaul Lin * (at your option) any later version. 10*463d47f6SMacpaul Lin * 11*463d47f6SMacpaul Lin * This program is distributed in the hope that it will be useful, 12*463d47f6SMacpaul Lin * but WITHOUT ANY WARRANTY; without even the implied warranty of 13*463d47f6SMacpaul Lin * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14*463d47f6SMacpaul Lin * GNU General Public License for more details. 15*463d47f6SMacpaul Lin * 16*463d47f6SMacpaul Lin * You should have received a copy of the GNU General Public License 17*463d47f6SMacpaul Lin * along with this program; if not, write to the Free Software 18*463d47f6SMacpaul Lin * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19*463d47f6SMacpaul Lin * 20*463d47f6SMacpaul Lin */ 21*463d47f6SMacpaul Lin 22*463d47f6SMacpaul Lin #include <common.h> 23*463d47f6SMacpaul Lin #include <command.h> 24*463d47f6SMacpaul Lin #include <image.h> 25*463d47f6SMacpaul Lin #include <u-boot/zlib.h> 26*463d47f6SMacpaul Lin #include <asm/byteorder.h> 27*463d47f6SMacpaul Lin 28*463d47f6SMacpaul Lin DECLARE_GLOBAL_DATA_PTR; 29*463d47f6SMacpaul Lin 30*463d47f6SMacpaul Lin #if defined(CONFIG_SETUP_MEMORY_TAGS) || \ 31*463d47f6SMacpaul Lin defined(CONFIG_CMDLINE_TAG) || \ 32*463d47f6SMacpaul Lin defined(CONFIG_INITRD_TAG) || \ 33*463d47f6SMacpaul Lin defined(CONFIG_SERIAL_TAG) || \ 34*463d47f6SMacpaul Lin defined(CONFIG_REVISION_TAG) 35*463d47f6SMacpaul Lin static void setup_start_tag(bd_t *bd); 36*463d47f6SMacpaul Lin 37*463d47f6SMacpaul Lin # ifdef CONFIG_SETUP_MEMORY_TAGS 38*463d47f6SMacpaul Lin static void setup_memory_tags(bd_t *bd); 39*463d47f6SMacpaul Lin # endif 40*463d47f6SMacpaul Lin static void setup_commandline_tag(bd_t *bd, char *commandline); 41*463d47f6SMacpaul Lin 42*463d47f6SMacpaul Lin # ifdef CONFIG_INITRD_TAG 43*463d47f6SMacpaul Lin static void setup_initrd_tag(bd_t *bd, ulong initrd_start, ulong initrd_end); 44*463d47f6SMacpaul Lin # endif 45*463d47f6SMacpaul Lin static void setup_end_tag(bd_t *bd); 46*463d47f6SMacpaul Lin 47*463d47f6SMacpaul Lin static struct tag *params; 48*463d47f6SMacpaul Lin #endif /* CONFIG_SETUP_MEMORY_TAGS || CONFIG_CMDLINE_TAG || CONFIG_INITRD_TAG */ 49*463d47f6SMacpaul Lin 50*463d47f6SMacpaul Lin int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images) 51*463d47f6SMacpaul Lin { 52*463d47f6SMacpaul Lin bd_t *bd = gd->bd; 53*463d47f6SMacpaul Lin char *s; 54*463d47f6SMacpaul Lin int machid = bd->bi_arch_number; 55*463d47f6SMacpaul Lin void (*theKernel)(int zero, int arch, uint params); 56*463d47f6SMacpaul Lin 57*463d47f6SMacpaul Lin #ifdef CONFIG_CMDLINE_TAG 58*463d47f6SMacpaul Lin char *commandline = getenv("bootargs"); 59*463d47f6SMacpaul Lin #endif 60*463d47f6SMacpaul Lin 61*463d47f6SMacpaul Lin if ((flag != 0) && (flag != BOOTM_STATE_OS_GO)) 62*463d47f6SMacpaul Lin return 1; 63*463d47f6SMacpaul Lin 64*463d47f6SMacpaul Lin theKernel = (void (*)(int, int, uint))images->ep; 65*463d47f6SMacpaul Lin 66*463d47f6SMacpaul Lin s = getenv("machid"); 67*463d47f6SMacpaul Lin if (s) { 68*463d47f6SMacpaul Lin machid = simple_strtoul(s, NULL, 16); 69*463d47f6SMacpaul Lin printf("Using machid 0x%x from environment\n", machid); 70*463d47f6SMacpaul Lin } 71*463d47f6SMacpaul Lin 72*463d47f6SMacpaul Lin show_boot_progress(15); 73*463d47f6SMacpaul Lin 74*463d47f6SMacpaul Lin debug("## Transferring control to Linux (at address %08lx) ...\n", 75*463d47f6SMacpaul Lin (ulong)theKernel); 76*463d47f6SMacpaul Lin 77*463d47f6SMacpaul Lin #if defined(CONFIG_SETUP_MEMORY_TAGS) || \ 78*463d47f6SMacpaul Lin defined(CONFIG_CMDLINE_TAG) || \ 79*463d47f6SMacpaul Lin defined(CONFIG_INITRD_TAG) || \ 80*463d47f6SMacpaul Lin defined(CONFIG_SERIAL_TAG) || \ 81*463d47f6SMacpaul Lin defined(CONFIG_REVISION_TAG) 82*463d47f6SMacpaul Lin setup_start_tag(bd); 83*463d47f6SMacpaul Lin #ifdef CONFIG_SERIAL_TAG 84*463d47f6SMacpaul Lin setup_serial_tag(¶ms); 85*463d47f6SMacpaul Lin #endif 86*463d47f6SMacpaul Lin #ifdef CONFIG_REVISION_TAG 87*463d47f6SMacpaul Lin setup_revision_tag(¶ms); 88*463d47f6SMacpaul Lin #endif 89*463d47f6SMacpaul Lin #ifdef CONFIG_SETUP_MEMORY_TAGS 90*463d47f6SMacpaul Lin setup_memory_tags(bd); 91*463d47f6SMacpaul Lin #endif 92*463d47f6SMacpaul Lin #ifdef CONFIG_CMDLINE_TAG 93*463d47f6SMacpaul Lin setup_commandline_tag(bd, commandline); 94*463d47f6SMacpaul Lin #endif 95*463d47f6SMacpaul Lin #ifdef CONFIG_INITRD_TAG 96*463d47f6SMacpaul Lin if (images->rd_start && images->rd_end) 97*463d47f6SMacpaul Lin setup_initrd_tag(bd, images->rd_start, images->rd_end); 98*463d47f6SMacpaul Lin #endif 99*463d47f6SMacpaul Lin setup_end_tag(bd); 100*463d47f6SMacpaul Lin #endif 101*463d47f6SMacpaul Lin 102*463d47f6SMacpaul Lin /* we assume that the kernel is in place */ 103*463d47f6SMacpaul Lin printf("\nStarting kernel ...\n\n"); 104*463d47f6SMacpaul Lin 105*463d47f6SMacpaul Lin #ifdef CONFIG_USB_DEVICE 106*463d47f6SMacpaul Lin { 107*463d47f6SMacpaul Lin extern void udc_disconnect(void); 108*463d47f6SMacpaul Lin udc_disconnect(); 109*463d47f6SMacpaul Lin } 110*463d47f6SMacpaul Lin #endif 111*463d47f6SMacpaul Lin 112*463d47f6SMacpaul Lin cleanup_before_linux(); 113*463d47f6SMacpaul Lin 114*463d47f6SMacpaul Lin theKernel(0, machid, bd->bi_boot_params); 115*463d47f6SMacpaul Lin /* does not return */ 116*463d47f6SMacpaul Lin 117*463d47f6SMacpaul Lin return 1; 118*463d47f6SMacpaul Lin } 119*463d47f6SMacpaul Lin 120*463d47f6SMacpaul Lin 121*463d47f6SMacpaul Lin #if defined(CONFIG_SETUP_MEMORY_TAGS) || \ 122*463d47f6SMacpaul Lin defined(CONFIG_CMDLINE_TAG) || \ 123*463d47f6SMacpaul Lin defined(CONFIG_INITRD_TAG) || \ 124*463d47f6SMacpaul Lin defined(CONFIG_SERIAL_TAG) || \ 125*463d47f6SMacpaul Lin defined(CONFIG_REVISION_TAG) 126*463d47f6SMacpaul Lin static void setup_start_tag(bd_t *bd) 127*463d47f6SMacpaul Lin { 128*463d47f6SMacpaul Lin params = (struct tag *)bd->bi_boot_params; 129*463d47f6SMacpaul Lin 130*463d47f6SMacpaul Lin params->hdr.tag = ATAG_CORE; 131*463d47f6SMacpaul Lin params->hdr.size = tag_size(tag_core); 132*463d47f6SMacpaul Lin 133*463d47f6SMacpaul Lin params->u.core.flags = 0; 134*463d47f6SMacpaul Lin params->u.core.pagesize = 0; 135*463d47f6SMacpaul Lin params->u.core.rootdev = 0; 136*463d47f6SMacpaul Lin 137*463d47f6SMacpaul Lin params = tag_next(params); 138*463d47f6SMacpaul Lin } 139*463d47f6SMacpaul Lin 140*463d47f6SMacpaul Lin 141*463d47f6SMacpaul Lin #ifdef CONFIG_SETUP_MEMORY_TAGS 142*463d47f6SMacpaul Lin static void setup_memory_tags(bd_t *bd) 143*463d47f6SMacpaul Lin { 144*463d47f6SMacpaul Lin int i; 145*463d47f6SMacpaul Lin 146*463d47f6SMacpaul Lin for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) { 147*463d47f6SMacpaul Lin params->hdr.tag = ATAG_MEM; 148*463d47f6SMacpaul Lin params->hdr.size = tag_size(tag_mem32); 149*463d47f6SMacpaul Lin 150*463d47f6SMacpaul Lin params->u.mem.start = bd->bi_dram[i].start; 151*463d47f6SMacpaul Lin params->u.mem.size = bd->bi_dram[i].size; 152*463d47f6SMacpaul Lin 153*463d47f6SMacpaul Lin params = tag_next(params); 154*463d47f6SMacpaul Lin } 155*463d47f6SMacpaul Lin } 156*463d47f6SMacpaul Lin #endif /* CONFIG_SETUP_MEMORY_TAGS */ 157*463d47f6SMacpaul Lin 158*463d47f6SMacpaul Lin 159*463d47f6SMacpaul Lin static void setup_commandline_tag(bd_t *bd, char *commandline) 160*463d47f6SMacpaul Lin { 161*463d47f6SMacpaul Lin char *p; 162*463d47f6SMacpaul Lin 163*463d47f6SMacpaul Lin if (!commandline) 164*463d47f6SMacpaul Lin return; 165*463d47f6SMacpaul Lin 166*463d47f6SMacpaul Lin /* eat leading white space */ 167*463d47f6SMacpaul Lin for (p = commandline; *p == ' '; p++) 168*463d47f6SMacpaul Lin ; 169*463d47f6SMacpaul Lin 170*463d47f6SMacpaul Lin /* skip non-existent command lines so the kernel will still 171*463d47f6SMacpaul Lin * use its default command line. 172*463d47f6SMacpaul Lin */ 173*463d47f6SMacpaul Lin if (*p == '\0') 174*463d47f6SMacpaul Lin return; 175*463d47f6SMacpaul Lin 176*463d47f6SMacpaul Lin params->hdr.tag = ATAG_CMDLINE; 177*463d47f6SMacpaul Lin params->hdr.size = 178*463d47f6SMacpaul Lin (sizeof(struct tag_header) + strlen(p) + 1 + 4) >> 2; 179*463d47f6SMacpaul Lin 180*463d47f6SMacpaul Lin strcpy(params->u.cmdline.cmdline, p) 181*463d47f6SMacpaul Lin ; 182*463d47f6SMacpaul Lin 183*463d47f6SMacpaul Lin params = tag_next(params); 184*463d47f6SMacpaul Lin } 185*463d47f6SMacpaul Lin 186*463d47f6SMacpaul Lin 187*463d47f6SMacpaul Lin #ifdef CONFIG_INITRD_TAG 188*463d47f6SMacpaul Lin static void setup_initrd_tag(bd_t *bd, ulong initrd_start, ulong initrd_end) 189*463d47f6SMacpaul Lin { 190*463d47f6SMacpaul Lin /* an ATAG_INITRD node tells the kernel where the compressed 191*463d47f6SMacpaul Lin * ramdisk can be found. ATAG_RDIMG is a better name, actually. 192*463d47f6SMacpaul Lin */ 193*463d47f6SMacpaul Lin params->hdr.tag = ATAG_INITRD2; 194*463d47f6SMacpaul Lin params->hdr.size = tag_size(tag_initrd); 195*463d47f6SMacpaul Lin 196*463d47f6SMacpaul Lin params->u.initrd.start = initrd_start; 197*463d47f6SMacpaul Lin params->u.initrd.size = initrd_end - initrd_start; 198*463d47f6SMacpaul Lin 199*463d47f6SMacpaul Lin params = tag_next(params); 200*463d47f6SMacpaul Lin } 201*463d47f6SMacpaul Lin #endif /* CONFIG_INITRD_TAG */ 202*463d47f6SMacpaul Lin 203*463d47f6SMacpaul Lin #ifdef CONFIG_SERIAL_TAG 204*463d47f6SMacpaul Lin void setup_serial_tag(struct tag **tmp) 205*463d47f6SMacpaul Lin { 206*463d47f6SMacpaul Lin struct tag *params = *tmp; 207*463d47f6SMacpaul Lin struct tag_serialnr serialnr; 208*463d47f6SMacpaul Lin void get_board_serial(struct tag_serialnr *serialnr); 209*463d47f6SMacpaul Lin 210*463d47f6SMacpaul Lin get_board_serial(&serialnr); 211*463d47f6SMacpaul Lin params->hdr.tag = ATAG_SERIAL; 212*463d47f6SMacpaul Lin params->hdr.size = tag_size(tag_serialnr); 213*463d47f6SMacpaul Lin params->u.serialnr.low = serialnr.low; 214*463d47f6SMacpaul Lin params->u.serialnr.high = serialnr.high; 215*463d47f6SMacpaul Lin params = tag_next(params); 216*463d47f6SMacpaul Lin *tmp = params; 217*463d47f6SMacpaul Lin } 218*463d47f6SMacpaul Lin #endif 219*463d47f6SMacpaul Lin 220*463d47f6SMacpaul Lin #ifdef CONFIG_REVISION_TAG 221*463d47f6SMacpaul Lin void setup_revision_tag(struct tag **in_params) 222*463d47f6SMacpaul Lin { 223*463d47f6SMacpaul Lin u32 rev = 0; 224*463d47f6SMacpaul Lin u32 get_board_rev(void); 225*463d47f6SMacpaul Lin 226*463d47f6SMacpaul Lin rev = get_board_rev(); 227*463d47f6SMacpaul Lin params->hdr.tag = ATAG_REVISION; 228*463d47f6SMacpaul Lin params->hdr.size = tag_size(tag_revision); 229*463d47f6SMacpaul Lin params->u.revision.rev = rev; 230*463d47f6SMacpaul Lin params = tag_next(params); 231*463d47f6SMacpaul Lin } 232*463d47f6SMacpaul Lin #endif /* CONFIG_REVISION_TAG */ 233*463d47f6SMacpaul Lin 234*463d47f6SMacpaul Lin 235*463d47f6SMacpaul Lin static void setup_end_tag(bd_t *bd) 236*463d47f6SMacpaul Lin { 237*463d47f6SMacpaul Lin params->hdr.tag = ATAG_NONE; 238*463d47f6SMacpaul Lin params->hdr.size = 0; 239*463d47f6SMacpaul Lin } 240*463d47f6SMacpaul Lin 241*463d47f6SMacpaul Lin #endif /* CONFIG_SETUP_MEMORY_TAGS || CONFIG_CMDLINE_TAG || CONFIG_INITRD_TAG */ 242