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