blob: aceed153d754cb20dd0f9990ac15cd6746b9fbff [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Chris Zankelc978b522016-08-10 18:36:44 +03002/*
3 * (C) Copyright 2008 - 2013 Tensilica Inc.
4 * (C) Copyright 2014 Cadence Design Systems Inc.
Chris Zankelc978b522016-08-10 18:36:44 +03005 */
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
16DECLARE_GLOBAL_DATA_PTR;
17
18/*
19 * Setup boot-parameters.
20 */
21
22static 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 *)&params->data = BP_VERSION;
27
28 return bp_tag_next(params);
29}
30
31static 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
39static 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
57static 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
77static 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
102static 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
116static 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
134int 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;
Simon Glass00caae62017-08-03 12:22:12 -0600138 char *commandline = env_get("bootargs");
Chris Zankelc978b522016-08-10 18:36:44 +0300139
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