1*c978b524SChris Zankel /* 2*c978b524SChris Zankel * (C) Copyright 2008 - 2013 Tensilica Inc. 3*c978b524SChris Zankel * (C) Copyright 2014 Cadence Design Systems Inc. 4*c978b524SChris Zankel * 5*c978b524SChris Zankel * SPDX-License-Identifier: GPL-2.0+ 6*c978b524SChris Zankel */ 7*c978b524SChris Zankel 8*c978b524SChris Zankel #include <common.h> 9*c978b524SChris Zankel #include <command.h> 10*c978b524SChris Zankel #include <u-boot/zlib.h> 11*c978b524SChris Zankel #include <asm/byteorder.h> 12*c978b524SChris Zankel #include <asm/addrspace.h> 13*c978b524SChris Zankel #include <asm/bootparam.h> 14*c978b524SChris Zankel #include <asm/cache.h> 15*c978b524SChris Zankel #include <image.h> 16*c978b524SChris Zankel 17*c978b524SChris Zankel DECLARE_GLOBAL_DATA_PTR; 18*c978b524SChris Zankel 19*c978b524SChris Zankel /* 20*c978b524SChris Zankel * Setup boot-parameters. 21*c978b524SChris Zankel */ 22*c978b524SChris Zankel 23*c978b524SChris Zankel static struct bp_tag *setup_first_tag(struct bp_tag *params) 24*c978b524SChris Zankel { 25*c978b524SChris Zankel params->id = BP_TAG_FIRST; 26*c978b524SChris Zankel params->size = sizeof(long); 27*c978b524SChris Zankel *(unsigned long *)¶ms->data = BP_VERSION; 28*c978b524SChris Zankel 29*c978b524SChris Zankel return bp_tag_next(params); 30*c978b524SChris Zankel } 31*c978b524SChris Zankel 32*c978b524SChris Zankel static struct bp_tag *setup_last_tag(struct bp_tag *params) 33*c978b524SChris Zankel { 34*c978b524SChris Zankel params->id = BP_TAG_LAST; 35*c978b524SChris Zankel params->size = 0; 36*c978b524SChris Zankel 37*c978b524SChris Zankel return bp_tag_next(params); 38*c978b524SChris Zankel } 39*c978b524SChris Zankel 40*c978b524SChris Zankel static struct bp_tag *setup_memory_tag(struct bp_tag *params) 41*c978b524SChris Zankel { 42*c978b524SChris Zankel struct bd_info *bd = gd->bd; 43*c978b524SChris Zankel struct meminfo *mem; 44*c978b524SChris Zankel 45*c978b524SChris Zankel params->id = BP_TAG_MEMORY; 46*c978b524SChris Zankel params->size = sizeof(struct meminfo); 47*c978b524SChris Zankel mem = (struct meminfo *)params->data; 48*c978b524SChris Zankel mem->type = MEMORY_TYPE_CONVENTIONAL; 49*c978b524SChris Zankel mem->start = bd->bi_memstart; 50*c978b524SChris Zankel mem->end = bd->bi_memstart + bd->bi_memsize; 51*c978b524SChris Zankel 52*c978b524SChris Zankel printf(" MEMORY: tag:0x%04x, type:0X%lx, start:0X%lx, end:0X%lx\n", 53*c978b524SChris Zankel BP_TAG_MEMORY, mem->type, mem->start, mem->end); 54*c978b524SChris Zankel 55*c978b524SChris Zankel return bp_tag_next(params); 56*c978b524SChris Zankel } 57*c978b524SChris Zankel 58*c978b524SChris Zankel static struct bp_tag *setup_commandline_tag(struct bp_tag *params, 59*c978b524SChris Zankel char *cmdline) 60*c978b524SChris Zankel { 61*c978b524SChris Zankel int len; 62*c978b524SChris Zankel 63*c978b524SChris Zankel if (!cmdline) 64*c978b524SChris Zankel return params; 65*c978b524SChris Zankel 66*c978b524SChris Zankel len = strlen(cmdline); 67*c978b524SChris Zankel 68*c978b524SChris Zankel params->id = BP_TAG_COMMAND_LINE; 69*c978b524SChris Zankel params->size = (len + 3) & -4; 70*c978b524SChris Zankel strcpy((char *)params->data, cmdline); 71*c978b524SChris Zankel 72*c978b524SChris Zankel printf(" COMMAND_LINE: tag:0x%04x, size:%u, data:'%s'\n", 73*c978b524SChris Zankel BP_TAG_COMMAND_LINE, params->size, cmdline); 74*c978b524SChris Zankel 75*c978b524SChris Zankel return bp_tag_next(params); 76*c978b524SChris Zankel } 77*c978b524SChris Zankel 78*c978b524SChris Zankel static struct bp_tag *setup_ramdisk_tag(struct bp_tag *params, 79*c978b524SChris Zankel unsigned long rd_start, 80*c978b524SChris Zankel unsigned long rd_end) 81*c978b524SChris Zankel { 82*c978b524SChris Zankel struct meminfo *mem; 83*c978b524SChris Zankel 84*c978b524SChris Zankel if (rd_start == rd_end) 85*c978b524SChris Zankel return params; 86*c978b524SChris Zankel 87*c978b524SChris Zankel /* Add a single banked memory */ 88*c978b524SChris Zankel 89*c978b524SChris Zankel params->id = BP_TAG_INITRD; 90*c978b524SChris Zankel params->size = sizeof(struct meminfo); 91*c978b524SChris Zankel 92*c978b524SChris Zankel mem = (struct meminfo *)params->data; 93*c978b524SChris Zankel mem->type = MEMORY_TYPE_CONVENTIONAL; 94*c978b524SChris Zankel mem->start = PHYSADDR(rd_start); 95*c978b524SChris Zankel mem->end = PHYSADDR(rd_end); 96*c978b524SChris Zankel 97*c978b524SChris Zankel printf(" INITRD: tag:0x%x, type:0X%04lx, start:0X%lx, end:0X%lx\n", 98*c978b524SChris Zankel BP_TAG_INITRD, mem->type, mem->start, mem->end); 99*c978b524SChris Zankel 100*c978b524SChris Zankel return bp_tag_next(params); 101*c978b524SChris Zankel } 102*c978b524SChris Zankel 103*c978b524SChris Zankel static struct bp_tag *setup_serial_tag(struct bp_tag *params) 104*c978b524SChris Zankel { 105*c978b524SChris Zankel params->id = BP_TAG_SERIAL_BAUDRATE; 106*c978b524SChris Zankel params->size = sizeof(unsigned long); 107*c978b524SChris Zankel params->data[0] = gd->baudrate; 108*c978b524SChris Zankel 109*c978b524SChris Zankel printf(" SERIAL_BAUDRATE: tag:0x%04x, size:%u, baudrate:%lu\n", 110*c978b524SChris Zankel BP_TAG_SERIAL_BAUDRATE, params->size, params->data[0]); 111*c978b524SChris Zankel 112*c978b524SChris Zankel return bp_tag_next(params); 113*c978b524SChris Zankel } 114*c978b524SChris Zankel 115*c978b524SChris Zankel #ifdef CONFIG_OF_LIBFDT 116*c978b524SChris Zankel 117*c978b524SChris Zankel static struct bp_tag *setup_fdt_tag(struct bp_tag *params, void *fdt_start) 118*c978b524SChris Zankel { 119*c978b524SChris Zankel params->id = BP_TAG_FDT; 120*c978b524SChris Zankel params->size = sizeof(unsigned long); 121*c978b524SChris Zankel params->data[0] = (unsigned long)fdt_start; 122*c978b524SChris Zankel 123*c978b524SChris Zankel printf(" FDT: tag:0x%04x, size:%u, start:0x%lx\n", 124*c978b524SChris Zankel BP_TAG_FDT, params->size, params->data[0]); 125*c978b524SChris Zankel 126*c978b524SChris Zankel return bp_tag_next(params); 127*c978b524SChris Zankel } 128*c978b524SChris Zankel 129*c978b524SChris Zankel #endif 130*c978b524SChris Zankel 131*c978b524SChris Zankel /* 132*c978b524SChris Zankel * Boot Linux. 133*c978b524SChris Zankel */ 134*c978b524SChris Zankel 135*c978b524SChris Zankel int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images) 136*c978b524SChris Zankel { 137*c978b524SChris Zankel struct bp_tag *params, *params_start; 138*c978b524SChris Zankel ulong initrd_start, initrd_end; 139*c978b524SChris Zankel char *commandline = getenv("bootargs"); 140*c978b524SChris Zankel 141*c978b524SChris Zankel if (!(flag & (BOOTM_STATE_OS_GO | BOOTM_STATE_OS_FAKE_GO))) 142*c978b524SChris Zankel return 0; 143*c978b524SChris Zankel 144*c978b524SChris Zankel show_boot_progress(15); 145*c978b524SChris Zankel 146*c978b524SChris Zankel if (images->rd_start) { 147*c978b524SChris Zankel initrd_start = images->rd_start; 148*c978b524SChris Zankel initrd_end = images->rd_end; 149*c978b524SChris Zankel } else { 150*c978b524SChris Zankel initrd_start = 0; 151*c978b524SChris Zankel initrd_end = 0; 152*c978b524SChris Zankel } 153*c978b524SChris Zankel 154*c978b524SChris Zankel params_start = (struct bp_tag *)gd->bd->bi_boot_params; 155*c978b524SChris Zankel params = params_start; 156*c978b524SChris Zankel params = setup_first_tag(params); 157*c978b524SChris Zankel params = setup_memory_tag(params); 158*c978b524SChris Zankel params = setup_commandline_tag(params, commandline); 159*c978b524SChris Zankel params = setup_serial_tag(params); 160*c978b524SChris Zankel 161*c978b524SChris Zankel if (initrd_start) 162*c978b524SChris Zankel params = setup_ramdisk_tag(params, initrd_start, initrd_end); 163*c978b524SChris Zankel 164*c978b524SChris Zankel #ifdef CONFIG_OF_LIBFDT 165*c978b524SChris Zankel if (images->ft_addr) 166*c978b524SChris Zankel params = setup_fdt_tag(params, images->ft_addr); 167*c978b524SChris Zankel #endif 168*c978b524SChris Zankel 169*c978b524SChris Zankel printf("\n"); 170*c978b524SChris Zankel 171*c978b524SChris Zankel params = setup_last_tag(params); 172*c978b524SChris Zankel 173*c978b524SChris Zankel show_boot_progress(15); 174*c978b524SChris Zankel 175*c978b524SChris Zankel printf("Transferring Control to Linux @0x%08lx ...\n\n", 176*c978b524SChris Zankel (ulong)images->ep); 177*c978b524SChris Zankel 178*c978b524SChris Zankel flush_dcache_range((unsigned long)params_start, (unsigned long)params); 179*c978b524SChris Zankel 180*c978b524SChris Zankel if (flag & BOOTM_STATE_OS_FAKE_GO) 181*c978b524SChris Zankel return 0; 182*c978b524SChris Zankel 183*c978b524SChris Zankel /* 184*c978b524SChris Zankel * _start() in vmlinux expects boot params in register a2. 185*c978b524SChris Zankel * NOTE: 186*c978b524SChris Zankel * Disable/delete your u-boot breakpoints before stepping into linux. 187*c978b524SChris Zankel */ 188*c978b524SChris Zankel asm volatile ("mov a2, %0\n\t" 189*c978b524SChris Zankel "jx %1\n\t" 190*c978b524SChris Zankel : : "a" (params_start), "a" (images->ep) 191*c978b524SChris Zankel : "a2"); 192*c978b524SChris Zankel 193*c978b524SChris Zankel /* Does not return */ 194*c978b524SChris Zankel 195*c978b524SChris Zankel return 1; 196*c978b524SChris Zankel } 197*c978b524SChris Zankel 198