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