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