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