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
setup_first_tag(struct bp_tag * params)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
setup_last_tag(struct bp_tag * params)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
setup_memory_tag(struct bp_tag * params)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
setup_commandline_tag(struct bp_tag * params,char * cmdline)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
setup_ramdisk_tag(struct bp_tag * params,unsigned long rd_start,unsigned long rd_end)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
setup_serial_tag(struct bp_tag * params)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
setup_fdt_tag(struct bp_tag * params,void * fdt_start)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
do_bootm_linux(int flag,int argc,char * argv[],bootm_headers_t * images)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