1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Copyright (c) 2021 Rockchip Electronics Co., Ltd
4*4882a593Smuzhiyun */
5*4882a593Smuzhiyun
6*4882a593Smuzhiyun #include <common.h>
7*4882a593Smuzhiyun #include <amp.h>
8*4882a593Smuzhiyun #include <bidram.h>
9*4882a593Smuzhiyun #include <boot_rkimg.h>
10*4882a593Smuzhiyun #include <config.h>
11*4882a593Smuzhiyun #include <sysmem.h>
12*4882a593Smuzhiyun #include <asm/gic.h>
13*4882a593Smuzhiyun #include <asm/io.h>
14*4882a593Smuzhiyun #include <asm/arch/rockchip_smccc.h>
15*4882a593Smuzhiyun
16*4882a593Smuzhiyun DECLARE_GLOBAL_DATA_PTR;
17*4882a593Smuzhiyun
18*4882a593Smuzhiyun /*
19*4882a593Smuzhiyun * [Design Principles]
20*4882a593Smuzhiyun *
21*4882a593Smuzhiyun * [amp.img]
22*4882a593Smuzhiyun * The amp image with FIT format which consists of non-linux firmwares.
23*4882a593Smuzhiyun * Please refer to: driver/cpu/amp.its.
24*4882a593Smuzhiyun *
25*4882a593Smuzhiyun * amp.img generation: ./tools/mkimage -f drivers/cpu/amp.its -E -p 0xe00 amp.img
26*4882a593Smuzhiyun *
27*4882a593Smuzhiyun * [linux]
28*4882a593Smuzhiyun * We still use the traditional solution for a better compatibility:
29*4882a593Smuzhiyun * boot.img/recovery.img with FIT format or Android format.
30*4882a593Smuzhiyun *
31*4882a593Smuzhiyun * The developer need add "/configurations/conf/linux" node to configure:
32*4882a593Smuzhiyun * description, arch, cpu, thumb, hyp, udelay(optional) properties.
33*4882a593Smuzhiyun * The addresses depend on U-Boot: kernel_addr_r, fdt_addr_r and
34*4882a593Smuzhiyun * ramdisk_addr_r. Please refer to: driver/cpu/amp.its.
35*4882a593Smuzhiyun *
36*4882a593Smuzhiyun * [memory management]
37*4882a593Smuzhiyun * U-Boot is not responsible for memory distribution/fixup any more, please
38*4882a593Smuzhiyun * handle this on kernel dts "/memory".
39*4882a593Smuzhiyun *
40*4882a593Smuzhiyun * [trust]
41*4882a593Smuzhiyun * The AMP feature requires trust support.
42*4882a593Smuzhiyun */
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun #define AMP_PART "amp"
45*4882a593Smuzhiyun #define FIT_HEADER_SIZE SZ_4K
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun #define gicd_readl(offset) readl((void *)GICD_BASE + (offset))
48*4882a593Smuzhiyun #define gicd_writel(v, offset) writel(v, (void *)GICD_BASE + (offset))
49*4882a593Smuzhiyun #define LINXU_AMP_NODES "/rockchip-amp/amp-cpus"
50*4882a593Smuzhiyun
51*4882a593Smuzhiyun typedef struct boot_args {
52*4882a593Smuzhiyun ulong arg0;
53*4882a593Smuzhiyun ulong arg1;
54*4882a593Smuzhiyun ulong arg2;
55*4882a593Smuzhiyun ulong arg3;
56*4882a593Smuzhiyun } boot_args_t;
57*4882a593Smuzhiyun
58*4882a593Smuzhiyun typedef struct boot_cpu {
59*4882a593Smuzhiyun u32 arch;
60*4882a593Smuzhiyun u32 state;
61*4882a593Smuzhiyun u32 entry;
62*4882a593Smuzhiyun u32 linux_os;
63*4882a593Smuzhiyun } boot_cpu_t;
64*4882a593Smuzhiyun
65*4882a593Smuzhiyun static boot_cpu_t g_bootcpu;
66*4882a593Smuzhiyun static u32 g_cpus_boot_by_linux[8];
67*4882a593Smuzhiyun
fit_get_u32_default(const void * fit,int noffset,const char * prop,u32 def)68*4882a593Smuzhiyun static u32 fit_get_u32_default(const void *fit, int noffset,
69*4882a593Smuzhiyun const char *prop, u32 def)
70*4882a593Smuzhiyun {
71*4882a593Smuzhiyun const fdt32_t *val;
72*4882a593Smuzhiyun
73*4882a593Smuzhiyun val = fdt_getprop(fit, noffset, prop, NULL);
74*4882a593Smuzhiyun if (!val)
75*4882a593Smuzhiyun return def;
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun return fdt32_to_cpu(*val);
78*4882a593Smuzhiyun }
79*4882a593Smuzhiyun
parse_cpus_boot_by_linux(void)80*4882a593Smuzhiyun static int parse_cpus_boot_by_linux(void)
81*4882a593Smuzhiyun {
82*4882a593Smuzhiyun const void *fdt = gd->fdt_blob;
83*4882a593Smuzhiyun int noffset, cpu, i = 0;
84*4882a593Smuzhiyun u64 mpidr;
85*4882a593Smuzhiyun
86*4882a593Smuzhiyun memset(g_cpus_boot_by_linux, 0xff, sizeof(g_cpus_boot_by_linux));
87*4882a593Smuzhiyun noffset = fdt_path_offset(fdt, LINXU_AMP_NODES);
88*4882a593Smuzhiyun if (noffset < 0)
89*4882a593Smuzhiyun return 0;
90*4882a593Smuzhiyun
91*4882a593Smuzhiyun fdt_for_each_subnode(cpu, fdt, noffset) {
92*4882a593Smuzhiyun mpidr = fdtdec_get_uint64(fdt, cpu, "id", 0xffffffff);
93*4882a593Smuzhiyun if (mpidr == 0xffffffff)
94*4882a593Smuzhiyun continue;
95*4882a593Smuzhiyun g_cpus_boot_by_linux[i++] = mpidr;
96*4882a593Smuzhiyun printf("CPU[0x%llx] is required boot by Linux\n", mpidr);
97*4882a593Smuzhiyun }
98*4882a593Smuzhiyun
99*4882a593Smuzhiyun return 0;
100*4882a593Smuzhiyun }
101*4882a593Smuzhiyun
load_linux_for_nonboot_cpu(u32 cpu,u32 aarch64,u32 load,u32 * entry,boot_args_t * args)102*4882a593Smuzhiyun static int load_linux_for_nonboot_cpu(u32 cpu, u32 aarch64, u32 load,
103*4882a593Smuzhiyun u32 *entry, boot_args_t *args)
104*4882a593Smuzhiyun {
105*4882a593Smuzhiyun static const char *boot_cmd[] = {
106*4882a593Smuzhiyun "boot_fit", "boot_android ${devtype} ${devnum}" };
107*4882a593Smuzhiyun int i, ret;
108*4882a593Smuzhiyun
109*4882a593Smuzhiyun env_set_hex("bootm_states_unmask", BOOTM_STATE_OS_GO);
110*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(boot_cmd); i++) {
111*4882a593Smuzhiyun ret = run_command(boot_cmd[i], 0);
112*4882a593Smuzhiyun if (!ret)
113*4882a593Smuzhiyun break;
114*4882a593Smuzhiyun }
115*4882a593Smuzhiyun env_set("bootm_states_unmask", NULL);
116*4882a593Smuzhiyun if (ret) {
117*4882a593Smuzhiyun AMP_E("Load linux failed, ret=%d\n", ret);
118*4882a593Smuzhiyun return ret;
119*4882a593Smuzhiyun }
120*4882a593Smuzhiyun
121*4882a593Smuzhiyun /* linux boot args */
122*4882a593Smuzhiyun if (aarch64) {
123*4882a593Smuzhiyun args->arg0 = (ulong)gd->fdt_blob;
124*4882a593Smuzhiyun args->arg1 = 0;
125*4882a593Smuzhiyun args->arg2 = 0;
126*4882a593Smuzhiyun } else {
127*4882a593Smuzhiyun args->arg0 = 0;
128*4882a593Smuzhiyun args->arg1 = 0;
129*4882a593Smuzhiyun args->arg2 = (ulong)gd->fdt_blob;
130*4882a593Smuzhiyun }
131*4882a593Smuzhiyun
132*4882a593Smuzhiyun /* don't need call cleanup_before_linux() as this nonboot cpu is clean */
133*4882a593Smuzhiyun board_quiesce_devices(&images);
134*4882a593Smuzhiyun flush_dcache_all();
135*4882a593Smuzhiyun
136*4882a593Smuzhiyun /* fixup: ramdisk/fdt/entry depend on U-Boot */
137*4882a593Smuzhiyun *entry = (u32)images.ep;
138*4882a593Smuzhiyun
139*4882a593Smuzhiyun return 0;
140*4882a593Smuzhiyun }
141*4882a593Smuzhiyun
is_default_pe_state(u32 pe_state)142*4882a593Smuzhiyun static int is_default_pe_state(u32 pe_state)
143*4882a593Smuzhiyun {
144*4882a593Smuzhiyun #ifdef CONFIG_ARM64
145*4882a593Smuzhiyun return (pe_state == PE_STATE(1, 1, 0, 0));
146*4882a593Smuzhiyun #else
147*4882a593Smuzhiyun return (pe_state == PE_STATE(0, 0, 0, 0));
148*4882a593Smuzhiyun #endif
149*4882a593Smuzhiyun }
150*4882a593Smuzhiyun
setup_sync_bits_for_linux(void)151*4882a593Smuzhiyun static void setup_sync_bits_for_linux(void)
152*4882a593Smuzhiyun {
153*4882a593Smuzhiyun u32 val, num_irq, offset;
154*4882a593Smuzhiyun
155*4882a593Smuzhiyun val = gicd_readl(GICD_CTLR);
156*4882a593Smuzhiyun val &= ~0x3;
157*4882a593Smuzhiyun gicd_writel(val, GICD_CTLR);
158*4882a593Smuzhiyun
159*4882a593Smuzhiyun num_irq = 32 * ((gicd_readl(GICD_TYPER) & 0x1F) + 1);
160*4882a593Smuzhiyun offset = ((num_irq - 1) / 4) * 4;
161*4882a593Smuzhiyun gicd_writel(0x0, GICD_IPRIORITYRn + offset);
162*4882a593Smuzhiyun }
163*4882a593Smuzhiyun
smc_cpu_on(u32 cpu,u32 pe_state,u32 entry,boot_args_t * args,bool is_linux)164*4882a593Smuzhiyun static int smc_cpu_on(u32 cpu, u32 pe_state, u32 entry,
165*4882a593Smuzhiyun boot_args_t *args, bool is_linux)
166*4882a593Smuzhiyun {
167*4882a593Smuzhiyun int ret;
168*4882a593Smuzhiyun
169*4882a593Smuzhiyun AMP_I("Brought up cpu[%x] with state 0x%x, entry 0x%08x ...",
170*4882a593Smuzhiyun cpu, pe_state, entry);
171*4882a593Smuzhiyun
172*4882a593Smuzhiyun /* if target pe state is default arch state, power up cpu directly */
173*4882a593Smuzhiyun if (is_default_pe_state(pe_state))
174*4882a593Smuzhiyun goto finish;
175*4882a593Smuzhiyun
176*4882a593Smuzhiyun ret = sip_smc_amp_cfg(AMP_PE_STATE, cpu, pe_state, 0);
177*4882a593Smuzhiyun if (ret) {
178*4882a593Smuzhiyun AMP_E("smc pe-state, ret=%d\n", ret);
179*4882a593Smuzhiyun return ret;
180*4882a593Smuzhiyun }
181*4882a593Smuzhiyun
182*4882a593Smuzhiyun /* only linux needs boot args */
183*4882a593Smuzhiyun if (!is_linux)
184*4882a593Smuzhiyun goto finish;
185*4882a593Smuzhiyun
186*4882a593Smuzhiyun ret = sip_smc_amp_cfg(AMP_BOOT_ARG01, cpu, args->arg0, args->arg1);
187*4882a593Smuzhiyun if (ret) {
188*4882a593Smuzhiyun AMP_E("smc boot arg01, ret=%d\n", ret);
189*4882a593Smuzhiyun return ret;
190*4882a593Smuzhiyun }
191*4882a593Smuzhiyun
192*4882a593Smuzhiyun ret = sip_smc_amp_cfg(AMP_BOOT_ARG23, cpu, args->arg2, args->arg3);
193*4882a593Smuzhiyun if (ret) {
194*4882a593Smuzhiyun AMP_E("smc boot arg23, ret=%d\n", ret);
195*4882a593Smuzhiyun return ret;
196*4882a593Smuzhiyun }
197*4882a593Smuzhiyun
198*4882a593Smuzhiyun finish:
199*4882a593Smuzhiyun ret = psci_cpu_on(cpu, entry);
200*4882a593Smuzhiyun if (ret) {
201*4882a593Smuzhiyun printf("cpu up failed, ret=%d\n", ret);
202*4882a593Smuzhiyun return ret;
203*4882a593Smuzhiyun }
204*4882a593Smuzhiyun printf("OK\n");
205*4882a593Smuzhiyun
206*4882a593Smuzhiyun return 0;
207*4882a593Smuzhiyun }
208*4882a593Smuzhiyun
fit_standalone_release(char * id,uintptr_t entry_point)209*4882a593Smuzhiyun __weak int fit_standalone_release(char *id, uintptr_t entry_point)
210*4882a593Smuzhiyun {
211*4882a593Smuzhiyun return 0;
212*4882a593Smuzhiyun }
213*4882a593Smuzhiyun
standalone_handler(const char * id,u32 entry_point,int data_size)214*4882a593Smuzhiyun static int standalone_handler(const char *id, u32 entry_point, int data_size)
215*4882a593Smuzhiyun {
216*4882a593Smuzhiyun int ret;
217*4882a593Smuzhiyun
218*4882a593Smuzhiyun if (!sysmem_alloc_base_by_name(id,
219*4882a593Smuzhiyun (phys_addr_t)entry_point, data_size))
220*4882a593Smuzhiyun return -ENXIO;
221*4882a593Smuzhiyun
222*4882a593Smuzhiyun printf("Handle standalone: '%s' at 0x%08x ...", id, entry_point);
223*4882a593Smuzhiyun
224*4882a593Smuzhiyun ret = fit_standalone_release((char *)id, entry_point);
225*4882a593Smuzhiyun if (ret) {
226*4882a593Smuzhiyun printf("failed, ret=%d\n", ret);
227*4882a593Smuzhiyun return ret;
228*4882a593Smuzhiyun }
229*4882a593Smuzhiyun printf("OK\n");
230*4882a593Smuzhiyun
231*4882a593Smuzhiyun return 0;
232*4882a593Smuzhiyun }
233*4882a593Smuzhiyun
brought_up_amp(void * fit,int noffset,boot_cpu_t * bootcpu,int is_linux)234*4882a593Smuzhiyun static int brought_up_amp(void *fit, int noffset,
235*4882a593Smuzhiyun boot_cpu_t *bootcpu, int is_linux)
236*4882a593Smuzhiyun {
237*4882a593Smuzhiyun const char *desc;
238*4882a593Smuzhiyun boot_args_t args;
239*4882a593Smuzhiyun u32 cpu, aarch64, hyp;
240*4882a593Smuzhiyun u32 load, thumb, us;
241*4882a593Smuzhiyun u32 pe_state, entry;
242*4882a593Smuzhiyun int boot_on;
243*4882a593Smuzhiyun int data_size;
244*4882a593Smuzhiyun int i, ret;
245*4882a593Smuzhiyun u8 type = -ENODATA;
246*4882a593Smuzhiyun u8 arch = -ENODATA;
247*4882a593Smuzhiyun
248*4882a593Smuzhiyun desc = fdt_getprop(fit, noffset, "description", NULL);
249*4882a593Smuzhiyun cpu = fit_get_u32_default(fit, noffset, "cpu", -ENODATA);
250*4882a593Smuzhiyun hyp = fit_get_u32_default(fit, noffset, "hyp", 0);
251*4882a593Smuzhiyun thumb = fit_get_u32_default(fit, noffset, "thumb", 0);
252*4882a593Smuzhiyun entry = load = fit_get_u32_default(fit, noffset, "load", -ENODATA);
253*4882a593Smuzhiyun us = fit_get_u32_default(fit, noffset, "udelay", 0);
254*4882a593Smuzhiyun boot_on = fit_get_u32_default(fit, noffset, "boot-on", 1);
255*4882a593Smuzhiyun fit_image_get_arch(fit, noffset, &arch);
256*4882a593Smuzhiyun fit_image_get_type(fit, noffset, &type);
257*4882a593Smuzhiyun fit_image_get_data_size(fit, noffset, &data_size);
258*4882a593Smuzhiyun memset(&args, 0, sizeof(args));
259*4882a593Smuzhiyun
260*4882a593Smuzhiyun /* standalone is simple, just handle it and then exit. Allow failure */
261*4882a593Smuzhiyun if (type == IH_TYPE_STANDALONE) {
262*4882a593Smuzhiyun if (!desc || load == -ENODATA) {
263*4882a593Smuzhiyun AMP_E("standalone: \"desc\" or \"load\" property missing!\n");
264*4882a593Smuzhiyun goto exit;
265*4882a593Smuzhiyun }
266*4882a593Smuzhiyun standalone_handler(desc, load, data_size);
267*4882a593Smuzhiyun goto exit;
268*4882a593Smuzhiyun }
269*4882a593Smuzhiyun
270*4882a593Smuzhiyun if (!desc || cpu == -ENODATA || arch == -ENODATA || type == -ENODATA ||
271*4882a593Smuzhiyun (load == -ENODATA && !is_linux)) {
272*4882a593Smuzhiyun AMP_E("Property missing!\n");
273*4882a593Smuzhiyun return -EINVAL;
274*4882a593Smuzhiyun }
275*4882a593Smuzhiyun aarch64 = (arch == IH_ARCH_ARM) ? 0 : 1;
276*4882a593Smuzhiyun pe_state = PE_STATE(aarch64, hyp, thumb, 0);
277*4882a593Smuzhiyun
278*4882a593Smuzhiyun #ifdef DEBUG
279*4882a593Smuzhiyun AMP_I(" desc: %s\n", desc);
280*4882a593Smuzhiyun AMP_I(" cpu: 0x%x\n", cpu);
281*4882a593Smuzhiyun AMP_I(" aarch64: %d\n", aarch64);
282*4882a593Smuzhiyun AMP_I(" hyp: %d\n", hyp);
283*4882a593Smuzhiyun AMP_I(" thumb: %d\n", thumb);
284*4882a593Smuzhiyun AMP_I(" load: 0x%08x\n", load);
285*4882a593Smuzhiyun AMP_I(" pe_state: 0x%08x\n", pe_state);
286*4882a593Smuzhiyun AMP_I(" linux-os: %d\n\n", is_linux);
287*4882a593Smuzhiyun #endif
288*4882a593Smuzhiyun
289*4882a593Smuzhiyun /* this cpu is boot cpu ? */
290*4882a593Smuzhiyun if ((read_mpidr() & 0x0fff) == cpu) {
291*4882a593Smuzhiyun bootcpu->arch = arch;
292*4882a593Smuzhiyun bootcpu->entry = entry;
293*4882a593Smuzhiyun bootcpu->state = pe_state;
294*4882a593Smuzhiyun bootcpu->linux_os = is_linux;
295*4882a593Smuzhiyun return 0;
296*4882a593Smuzhiyun }
297*4882a593Smuzhiyun
298*4882a593Smuzhiyun /* === only nonboot cpu can reach here === */
299*4882a593Smuzhiyun
300*4882a593Smuzhiyun /* load or check */
301*4882a593Smuzhiyun if (is_linux) {
302*4882a593Smuzhiyun ret = load_linux_for_nonboot_cpu(cpu,
303*4882a593Smuzhiyun aarch64, load, &entry, &args);
304*4882a593Smuzhiyun if (ret)
305*4882a593Smuzhiyun return ret;
306*4882a593Smuzhiyun /*
307*4882a593Smuzhiyun * Must setup before jump to linux.
308*4882a593Smuzhiyun * This is an appointment on RK amp solution to handle
309*4882a593Smuzhiyun * GIC configure competition.
310*4882a593Smuzhiyun */
311*4882a593Smuzhiyun setup_sync_bits_for_linux();
312*4882a593Smuzhiyun } else {
313*4882a593Smuzhiyun if (!sysmem_alloc_base_by_name(desc,
314*4882a593Smuzhiyun (phys_addr_t)load, data_size))
315*4882a593Smuzhiyun return -ENXIO;
316*4882a593Smuzhiyun }
317*4882a593Smuzhiyun
318*4882a593Smuzhiyun /* If linux assign the boot-on state, use it */
319*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(g_cpus_boot_by_linux); i++) {
320*4882a593Smuzhiyun if (cpu == g_cpus_boot_by_linux[i]) {
321*4882a593Smuzhiyun boot_on = 0;
322*4882a593Smuzhiyun break;
323*4882a593Smuzhiyun }
324*4882a593Smuzhiyun }
325*4882a593Smuzhiyun
326*4882a593Smuzhiyun if (!boot_on)
327*4882a593Smuzhiyun return 0;
328*4882a593Smuzhiyun
329*4882a593Smuzhiyun /* boot now */
330*4882a593Smuzhiyun ret = smc_cpu_on(cpu, pe_state, entry, &args, is_linux);
331*4882a593Smuzhiyun if (ret)
332*4882a593Smuzhiyun return ret;
333*4882a593Smuzhiyun exit:
334*4882a593Smuzhiyun if (us)
335*4882a593Smuzhiyun udelay(us);
336*4882a593Smuzhiyun
337*4882a593Smuzhiyun return 0;
338*4882a593Smuzhiyun }
339*4882a593Smuzhiyun
brought_up_all_amp(void * fit,const char * fit_uname_cfg)340*4882a593Smuzhiyun static int brought_up_all_amp(void *fit, const char *fit_uname_cfg)
341*4882a593Smuzhiyun {
342*4882a593Smuzhiyun int loadables_index;
343*4882a593Smuzhiyun int linux_noffset;
344*4882a593Smuzhiyun int conf_noffset;
345*4882a593Smuzhiyun int cpu_noffset;
346*4882a593Smuzhiyun int ret;
347*4882a593Smuzhiyun const char *uname;
348*4882a593Smuzhiyun
349*4882a593Smuzhiyun conf_noffset = fit_conf_get_node(fit, fit_uname_cfg);
350*4882a593Smuzhiyun if (conf_noffset < 0)
351*4882a593Smuzhiyun return conf_noffset;
352*4882a593Smuzhiyun
353*4882a593Smuzhiyun linux_noffset = fdt_subnode_offset(fit, conf_noffset, "linux");
354*4882a593Smuzhiyun if (linux_noffset > 0) {
355*4882a593Smuzhiyun ret = brought_up_amp(fit, linux_noffset, &g_bootcpu, 1);
356*4882a593Smuzhiyun if (ret)
357*4882a593Smuzhiyun return ret;
358*4882a593Smuzhiyun }
359*4882a593Smuzhiyun
360*4882a593Smuzhiyun for (loadables_index = 0;
361*4882a593Smuzhiyun uname = fdt_stringlist_get(fit, conf_noffset,
362*4882a593Smuzhiyun FIT_LOADABLE_PROP, loadables_index, NULL), uname;
363*4882a593Smuzhiyun loadables_index++) {
364*4882a593Smuzhiyun cpu_noffset = fit_image_get_node(fit, uname);
365*4882a593Smuzhiyun if (cpu_noffset < 0)
366*4882a593Smuzhiyun return cpu_noffset;
367*4882a593Smuzhiyun
368*4882a593Smuzhiyun ret = brought_up_amp(fit, cpu_noffset, &g_bootcpu, 0);
369*4882a593Smuzhiyun if (ret)
370*4882a593Smuzhiyun return ret;
371*4882a593Smuzhiyun }
372*4882a593Smuzhiyun
373*4882a593Smuzhiyun /* === only boot cpu can reach here === */
374*4882a593Smuzhiyun
375*4882a593Smuzhiyun if (!g_bootcpu.linux_os && g_bootcpu.entry) {
376*4882a593Smuzhiyun flush_dcache_all();
377*4882a593Smuzhiyun AMP_I("Brought up cpu[%x, self] with state 0x%x, entry 0x%08x ...",
378*4882a593Smuzhiyun (u32)read_mpidr() & 0x0fff, g_bootcpu.state, g_bootcpu.entry);
379*4882a593Smuzhiyun cleanup_before_linux();
380*4882a593Smuzhiyun printf("OK\n");
381*4882a593Smuzhiyun #ifdef CONFIG_ARM64
382*4882a593Smuzhiyun armv8_switch_to_el2(0, 0, 0, g_bootcpu.state, (u64)g_bootcpu.entry,
383*4882a593Smuzhiyun g_bootcpu.arch == IH_ARCH_ARM ? ES_TO_AARCH32 : ES_TO_AARCH64);
384*4882a593Smuzhiyun #else
385*4882a593Smuzhiyun void (*armv7_entry)(void);
386*4882a593Smuzhiyun
387*4882a593Smuzhiyun armv7_entry = (void (*)(void))g_bootcpu.entry;
388*4882a593Smuzhiyun armv7_entry();
389*4882a593Smuzhiyun #endif
390*4882a593Smuzhiyun }
391*4882a593Smuzhiyun
392*4882a593Smuzhiyun /* return: boot cpu continue to boot linux */
393*4882a593Smuzhiyun return 0;
394*4882a593Smuzhiyun }
395*4882a593Smuzhiyun
amp_cpus_on(void)396*4882a593Smuzhiyun int amp_cpus_on(void)
397*4882a593Smuzhiyun {
398*4882a593Smuzhiyun struct blk_desc *dev_desc;
399*4882a593Smuzhiyun bootm_headers_t images;
400*4882a593Smuzhiyun disk_partition_t part;
401*4882a593Smuzhiyun void *hdr, *fit;
402*4882a593Smuzhiyun int offset, cnt;
403*4882a593Smuzhiyun int totalsize;
404*4882a593Smuzhiyun int ret = 0;
405*4882a593Smuzhiyun
406*4882a593Smuzhiyun dev_desc = rockchip_get_bootdev();
407*4882a593Smuzhiyun if (!dev_desc)
408*4882a593Smuzhiyun return -EIO;
409*4882a593Smuzhiyun
410*4882a593Smuzhiyun if (part_get_info_by_name(dev_desc, AMP_PART, &part) < 0)
411*4882a593Smuzhiyun return -ENODEV;
412*4882a593Smuzhiyun
413*4882a593Smuzhiyun hdr = memalign(ARCH_DMA_MINALIGN, FIT_HEADER_SIZE);
414*4882a593Smuzhiyun if (!hdr)
415*4882a593Smuzhiyun return -ENOMEM;
416*4882a593Smuzhiyun
417*4882a593Smuzhiyun /* get totalsize */
418*4882a593Smuzhiyun offset = part.start;
419*4882a593Smuzhiyun cnt = DIV_ROUND_UP(FIT_HEADER_SIZE, part.blksz);
420*4882a593Smuzhiyun if (blk_dread(dev_desc, offset, cnt, hdr) != cnt) {
421*4882a593Smuzhiyun ret = -EIO;
422*4882a593Smuzhiyun goto out2;
423*4882a593Smuzhiyun }
424*4882a593Smuzhiyun
425*4882a593Smuzhiyun if (fdt_check_header(hdr)) {
426*4882a593Smuzhiyun AMP_E("Not fit\n");
427*4882a593Smuzhiyun ret = -EINVAL;
428*4882a593Smuzhiyun goto out2;
429*4882a593Smuzhiyun }
430*4882a593Smuzhiyun
431*4882a593Smuzhiyun if (fit_get_totalsize(hdr, &totalsize)) {
432*4882a593Smuzhiyun AMP_E("No totalsize\n");
433*4882a593Smuzhiyun ret = -EINVAL;
434*4882a593Smuzhiyun goto out2;
435*4882a593Smuzhiyun }
436*4882a593Smuzhiyun
437*4882a593Smuzhiyun /* load image */
438*4882a593Smuzhiyun fit = memalign(ARCH_DMA_MINALIGN, ALIGN(totalsize, part.blksz));
439*4882a593Smuzhiyun if (!fit) {
440*4882a593Smuzhiyun printf("No memory\n");
441*4882a593Smuzhiyun ret = -ENOMEM;
442*4882a593Smuzhiyun goto out2;
443*4882a593Smuzhiyun }
444*4882a593Smuzhiyun
445*4882a593Smuzhiyun memcpy(fit, hdr, FIT_HEADER_SIZE);
446*4882a593Smuzhiyun
447*4882a593Smuzhiyun offset += cnt;
448*4882a593Smuzhiyun cnt = DIV_ROUND_UP(totalsize, part.blksz) - cnt;
449*4882a593Smuzhiyun if (blk_dread(dev_desc, offset, cnt, fit + FIT_HEADER_SIZE) != cnt) {
450*4882a593Smuzhiyun ret = -EIO;
451*4882a593Smuzhiyun goto out1;
452*4882a593Smuzhiyun }
453*4882a593Smuzhiyun
454*4882a593Smuzhiyun /* prase linux info */
455*4882a593Smuzhiyun parse_cpus_boot_by_linux();
456*4882a593Smuzhiyun
457*4882a593Smuzhiyun /* Load loadables */
458*4882a593Smuzhiyun memset(&images, 0, sizeof(images));
459*4882a593Smuzhiyun images.fit_uname_cfg = "conf";
460*4882a593Smuzhiyun images.fit_hdr_os = fit;
461*4882a593Smuzhiyun images.verify = 1;
462*4882a593Smuzhiyun ret = boot_get_loadable(0, NULL, &images, IH_ARCH_DEFAULT, NULL, NULL);
463*4882a593Smuzhiyun if (ret) {
464*4882a593Smuzhiyun AMP_E("Load loadables, ret=%d\n", ret);
465*4882a593Smuzhiyun goto out1;
466*4882a593Smuzhiyun }
467*4882a593Smuzhiyun flush_dcache_all();
468*4882a593Smuzhiyun
469*4882a593Smuzhiyun /* Wakeup */
470*4882a593Smuzhiyun ret = brought_up_all_amp(images.fit_hdr_os, images.fit_uname_cfg);
471*4882a593Smuzhiyun if (ret)
472*4882a593Smuzhiyun AMP_E("Brought up amps, ret=%d\n", ret);
473*4882a593Smuzhiyun out1:
474*4882a593Smuzhiyun free(fit);
475*4882a593Smuzhiyun out2:
476*4882a593Smuzhiyun free(hdr);
477*4882a593Smuzhiyun
478*4882a593Smuzhiyun return ret;
479*4882a593Smuzhiyun }
480*4882a593Smuzhiyun
arm64_switch_amp_pe(bootm_headers_t * images)481*4882a593Smuzhiyun int arm64_switch_amp_pe(bootm_headers_t *images)
482*4882a593Smuzhiyun {
483*4882a593Smuzhiyun images->os.arch = g_bootcpu.arch;
484*4882a593Smuzhiyun return g_bootcpu.state;
485*4882a593Smuzhiyun }
486*4882a593Smuzhiyun
487