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