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