xref: /OK3568_Linux_fs/u-boot/drivers/cpu/rockchip_amp.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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