xref: /rk3399_rockchip-uboot/drivers/cpu/rockchip_amp.c (revision b8fb8531a3a1c8e5dd51b11fd128471c45e3ed0c)
14388decaSJoseph Chen // SPDX-License-Identifier: GPL-2.0
24388decaSJoseph Chen /*
331f8f6ebSJoseph Chen  * Copyright (c) 2021 Rockchip Electronics Co., Ltd
44388decaSJoseph Chen  */
531f8f6ebSJoseph Chen 
64388decaSJoseph Chen #include <common.h>
74388decaSJoseph Chen #include <amp.h>
84388decaSJoseph Chen #include <bidram.h>
931f8f6ebSJoseph Chen #include <boot_rkimg.h>
1049cfbee5SJoseph Chen #include <config.h>
114388decaSJoseph Chen #include <sysmem.h>
1249cfbee5SJoseph Chen #include <asm/gic.h>
1349cfbee5SJoseph Chen #include <asm/io.h>
144388decaSJoseph Chen #include <asm/arch/rockchip_smccc.h>
154388decaSJoseph Chen 
16d184e484SJoseph Chen DECLARE_GLOBAL_DATA_PTR;
17d184e484SJoseph Chen 
18bb4a1f43SJoseph Chen /*
19bb4a1f43SJoseph Chen  * [Design Principles]
20bb4a1f43SJoseph Chen  *
21bb4a1f43SJoseph Chen  * [amp.img]
22bb4a1f43SJoseph Chen  *	The amp image with FIT format which consists of non-linux firmwares.
23bb4a1f43SJoseph Chen  *	Please refer to: driver/cpu/amp.its.
24bb4a1f43SJoseph Chen  *
25bb4a1f43SJoseph Chen  *	amp.img generation: ./tools/mkimage -f drivers/cpu/amp.its -E -p 0xe00 amp.img
26bb4a1f43SJoseph Chen  *
27bb4a1f43SJoseph Chen  * [linux]
28bb4a1f43SJoseph Chen  *	We still use the traditional solution for a better compatibility:
29bb4a1f43SJoseph Chen  *	boot.img/recovery.img with FIT format or Android format.
30bb4a1f43SJoseph Chen  *
31bb4a1f43SJoseph Chen  *	The developer need add "/configurations/conf/linux" node to configure:
32bb4a1f43SJoseph Chen  *	description, arch, cpu, thumb, hyp, udelay(optional) properties.
33bb4a1f43SJoseph Chen  *	The addresses depend on U-Boot: kernel_addr_r, fdt_addr_r and
34bb4a1f43SJoseph Chen  *	ramdisk_addr_r. Please refer to: driver/cpu/amp.its.
35bb4a1f43SJoseph Chen  *
36bb4a1f43SJoseph Chen  * [memory management]
37bb4a1f43SJoseph Chen  *	U-Boot is not responsible for memory distribution/fixup any more, please
38bb4a1f43SJoseph Chen  *	handle this on kernel dts "/memory".
39bb4a1f43SJoseph Chen  *
40bb4a1f43SJoseph Chen  * [trust]
41bb4a1f43SJoseph Chen  *	The AMP feature requires trust support.
42bb4a1f43SJoseph Chen  */
43bb4a1f43SJoseph Chen 
4431f8f6ebSJoseph Chen #define AMP_PART		"amp"
45043d91f2SJoseph Chen #define FIT_HEADER_SIZE		SZ_4K
46043d91f2SJoseph Chen 
4749cfbee5SJoseph Chen #define gicd_readl(offset)	readl((void *)GICD_BASE + (offset))
4849cfbee5SJoseph Chen #define gicd_writel(v, offset)	writel(v, (void *)GICD_BASE + (offset))
49d184e484SJoseph Chen #define LINXU_AMP_NODES		"/rockchip-amp/amp-cpus"
504388decaSJoseph Chen 
51bb4a1f43SJoseph Chen typedef struct boot_args {
52bb4a1f43SJoseph Chen 	ulong arg0;
53bb4a1f43SJoseph Chen 	ulong arg1;
54bb4a1f43SJoseph Chen 	ulong arg2;
55bb4a1f43SJoseph Chen 	ulong arg3;
56bb4a1f43SJoseph Chen } boot_args_t;
57bb4a1f43SJoseph Chen 
58bb4a1f43SJoseph Chen typedef struct boot_cpu {
59bb4a1f43SJoseph Chen 	u32 arch;
60bb4a1f43SJoseph Chen 	u32 state;
61bb4a1f43SJoseph Chen 	u32 entry;
62bb4a1f43SJoseph Chen 	u32 linux_os;
63bb4a1f43SJoseph Chen } boot_cpu_t;
64bb4a1f43SJoseph Chen 
65bb4a1f43SJoseph Chen static boot_cpu_t g_bootcpu;
66d184e484SJoseph Chen static u32 g_cpus_boot_by_linux[8];
6731f8f6ebSJoseph Chen 
6831f8f6ebSJoseph Chen static u32 fit_get_u32_default(const void *fit, int noffset,
6931f8f6ebSJoseph Chen 			       const char *prop, u32 def)
700df2c3dfSJoseph Chen {
7131f8f6ebSJoseph Chen 	const fdt32_t *val;
720df2c3dfSJoseph Chen 
7331f8f6ebSJoseph Chen 	val = fdt_getprop(fit, noffset, prop, NULL);
7431f8f6ebSJoseph Chen 	if (!val)
7531f8f6ebSJoseph Chen 		return def;
760df2c3dfSJoseph Chen 
7731f8f6ebSJoseph Chen 	return fdt32_to_cpu(*val);
780df2c3dfSJoseph Chen }
790df2c3dfSJoseph Chen 
80d184e484SJoseph Chen static int parse_cpus_boot_by_linux(void)
81d184e484SJoseph Chen {
82d184e484SJoseph Chen 	const void *fdt = gd->fdt_blob;
83cc173a5cSJoseph Chen 	int noffset, cpu, i = 0;
84cc173a5cSJoseph Chen 	u64 mpidr;
85d184e484SJoseph Chen 
86d184e484SJoseph Chen 	memset(g_cpus_boot_by_linux, 0xff, sizeof(g_cpus_boot_by_linux));
87d184e484SJoseph Chen 	noffset = fdt_path_offset(fdt, LINXU_AMP_NODES);
88d184e484SJoseph Chen 	if (noffset < 0)
89d184e484SJoseph Chen 		return 0;
90d184e484SJoseph Chen 
91d184e484SJoseph Chen 	fdt_for_each_subnode(cpu, fdt, noffset) {
92cc173a5cSJoseph Chen 		mpidr = fdtdec_get_uint64(fdt, cpu, "id", 0xffffffff);
93d184e484SJoseph Chen 		if (mpidr == 0xffffffff)
94d184e484SJoseph Chen 			continue;
95d184e484SJoseph Chen 		g_cpus_boot_by_linux[i++] = mpidr;
965f160584SJoseph Chen 		printf("CPU[0x%llx] is required boot by Linux\n", mpidr);
97d184e484SJoseph Chen 	}
98d184e484SJoseph Chen 
99d184e484SJoseph Chen 	return 0;
100d184e484SJoseph Chen }
101d184e484SJoseph Chen 
102bb4a1f43SJoseph Chen static int load_linux_for_nonboot_cpu(u32 cpu, u32 aarch64, u32 load,
103bb4a1f43SJoseph Chen 				      u32 *entry, boot_args_t *args)
1044388decaSJoseph Chen {
105bb4a1f43SJoseph Chen 	static const char *boot_cmd[] = {
106bb4a1f43SJoseph Chen 		"boot_fit", "boot_android ${devtype} ${devnum}" };
107bb4a1f43SJoseph Chen 	int i, ret;
108bb4a1f43SJoseph Chen 
109bb4a1f43SJoseph Chen 	env_set_hex("bootm_states_unmask", BOOTM_STATE_OS_GO);
110bb4a1f43SJoseph Chen 	for (i = 0; i < ARRAY_SIZE(boot_cmd); i++) {
111bb4a1f43SJoseph Chen 		ret = run_command(boot_cmd[i], 0);
112bb4a1f43SJoseph Chen 		if (!ret)
113bb4a1f43SJoseph Chen 			break;
114bb4a1f43SJoseph Chen 	}
115bb4a1f43SJoseph Chen 	env_set("bootm_states_unmask", NULL);
116bb4a1f43SJoseph Chen 	if (ret) {
117bb4a1f43SJoseph Chen 		AMP_E("Load linux failed, ret=%d\n", ret);
118bb4a1f43SJoseph Chen 		return ret;
119bb4a1f43SJoseph Chen 	}
120bb4a1f43SJoseph Chen 
121bb4a1f43SJoseph Chen 	/* linux boot args */
122bb4a1f43SJoseph Chen 	if (aarch64) {
123bb4a1f43SJoseph Chen 		args->arg0 = (ulong)gd->fdt_blob;
124bb4a1f43SJoseph Chen 		args->arg1 = 0;
125bb4a1f43SJoseph Chen 		args->arg2 = 0;
126bb4a1f43SJoseph Chen 	} else {
127bb4a1f43SJoseph Chen 		args->arg0 = 0;
128bb4a1f43SJoseph Chen 		args->arg1 = 0;
129bb4a1f43SJoseph Chen 		args->arg2 = (ulong)gd->fdt_blob;
130bb4a1f43SJoseph Chen 	}
131bb4a1f43SJoseph Chen 
132bb4a1f43SJoseph Chen 	/* don't need call cleanup_before_linux() as this nonboot cpu is clean */
133bb4a1f43SJoseph Chen 	board_quiesce_devices(&images);
134bb4a1f43SJoseph Chen 	flush_dcache_all();
135bb4a1f43SJoseph Chen 
136bb4a1f43SJoseph Chen 	/* fixup: ramdisk/fdt/entry depend on U-Boot */
13782b7aaedSJoseph Chen 	*entry = (u32)images.ep;
138bb4a1f43SJoseph Chen 
139bb4a1f43SJoseph Chen 	return 0;
140bb4a1f43SJoseph Chen }
141bb4a1f43SJoseph Chen 
142bb4a1f43SJoseph Chen static int is_default_pe_state(u32 pe_state)
143bb4a1f43SJoseph Chen {
144bb4a1f43SJoseph Chen #ifdef CONFIG_ARM64
145bb4a1f43SJoseph Chen 	return (pe_state == PE_STATE(1, 1, 0, 0));
146bb4a1f43SJoseph Chen #else
147bb4a1f43SJoseph Chen 	return (pe_state == PE_STATE(0, 0, 0, 0));
148bb4a1f43SJoseph Chen #endif
149bb4a1f43SJoseph Chen }
150bb4a1f43SJoseph Chen 
15149cfbee5SJoseph Chen static void setup_sync_bits_for_linux(void)
15249cfbee5SJoseph Chen {
15349cfbee5SJoseph Chen 	u32 val, num_irq, offset;
15449cfbee5SJoseph Chen 
15549cfbee5SJoseph Chen 	val = gicd_readl(GICD_CTLR);
15649cfbee5SJoseph Chen 	val &= ~0x3;
15749cfbee5SJoseph Chen 	gicd_writel(val, GICD_CTLR);
15849cfbee5SJoseph Chen 
15949cfbee5SJoseph Chen 	num_irq = 32 * ((gicd_readl(GICD_TYPER) & 0x1F) + 1);
16049cfbee5SJoseph Chen 	offset = ((num_irq - 1) / 4) * 4;
16149cfbee5SJoseph Chen 	gicd_writel(0x0, GICD_IPRIORITYRn + offset);
16249cfbee5SJoseph Chen }
16349cfbee5SJoseph Chen 
164257f4b84SJoseph Chen static int smc_cpu_on(u32 cpu, u32 pe_state, u32 entry,
165257f4b84SJoseph Chen 		      boot_args_t *args, bool is_linux)
166bb4a1f43SJoseph Chen {
16731f8f6ebSJoseph Chen 	int ret;
1684388decaSJoseph Chen 
169bb4a1f43SJoseph Chen 	AMP_I("Brought up cpu[%x] with state 0x%x, entry 0x%08x ...",
170bb4a1f43SJoseph Chen 	      cpu, pe_state, entry);
171bb4a1f43SJoseph Chen 
172257f4b84SJoseph Chen 	/* if target pe state is default arch state, power up cpu directly */
173bb4a1f43SJoseph Chen 	if (is_default_pe_state(pe_state))
174bb4a1f43SJoseph Chen 		goto finish;
175bb4a1f43SJoseph Chen 
176bb4a1f43SJoseph Chen 	ret = sip_smc_amp_cfg(AMP_PE_STATE, cpu, pe_state, 0);
177bb4a1f43SJoseph Chen 	if (ret) {
178bb4a1f43SJoseph Chen 		AMP_E("smc pe-state, ret=%d\n", ret);
179bb4a1f43SJoseph Chen 		return ret;
180bb4a1f43SJoseph Chen 	}
181bb4a1f43SJoseph Chen 
182257f4b84SJoseph Chen 	/* only linux needs boot args */
183257f4b84SJoseph Chen 	if (!is_linux)
184257f4b84SJoseph Chen 		goto finish;
185257f4b84SJoseph Chen 
186bb4a1f43SJoseph Chen 	ret = sip_smc_amp_cfg(AMP_BOOT_ARG01, cpu, args->arg0, args->arg1);
187bb4a1f43SJoseph Chen 	if (ret) {
188bb4a1f43SJoseph Chen 		AMP_E("smc boot arg01, ret=%d\n", ret);
189bb4a1f43SJoseph Chen 		return ret;
190bb4a1f43SJoseph Chen 	}
191bb4a1f43SJoseph Chen 
192bb4a1f43SJoseph Chen 	ret = sip_smc_amp_cfg(AMP_BOOT_ARG23, cpu, args->arg2, args->arg3);
193bb4a1f43SJoseph Chen 	if (ret) {
194bb4a1f43SJoseph Chen 		AMP_E("smc boot arg23, ret=%d\n", ret);
195bb4a1f43SJoseph Chen 		return ret;
196bb4a1f43SJoseph Chen 	}
197bb4a1f43SJoseph Chen 
198bb4a1f43SJoseph Chen finish:
199bb4a1f43SJoseph Chen 	ret = psci_cpu_on(cpu, entry);
200bb4a1f43SJoseph Chen 	if (ret) {
201bb4a1f43SJoseph Chen 		printf("cpu up failed, ret=%d\n", ret);
202bb4a1f43SJoseph Chen 		return ret;
203bb4a1f43SJoseph Chen 	}
204bb4a1f43SJoseph Chen 	printf("OK\n");
205bb4a1f43SJoseph Chen 
206bb4a1f43SJoseph Chen 	return 0;
207bb4a1f43SJoseph Chen }
208bb4a1f43SJoseph Chen 
209*b8fb8531SJoseph Chen __weak int fit_standalone_release(char *id, uintptr_t entry_point)
210*b8fb8531SJoseph Chen {
211*b8fb8531SJoseph Chen 	return 0;
212*b8fb8531SJoseph Chen }
213*b8fb8531SJoseph Chen 
214*b8fb8531SJoseph Chen static int standalone_handler(const char *id, u32 entry_point, int data_size)
215*b8fb8531SJoseph Chen {
216*b8fb8531SJoseph Chen 	int ret;
217*b8fb8531SJoseph Chen 
218*b8fb8531SJoseph Chen 	if (!sysmem_alloc_base_by_name(id,
219*b8fb8531SJoseph Chen 			(phys_addr_t)entry_point, data_size))
220*b8fb8531SJoseph Chen 		return -ENXIO;
221*b8fb8531SJoseph Chen 
222*b8fb8531SJoseph Chen 	printf("Handle standalone: '%s' at 0x%08x ...", id, entry_point);
223*b8fb8531SJoseph Chen 
224*b8fb8531SJoseph Chen 	ret = fit_standalone_release((char *)id, entry_point);
225*b8fb8531SJoseph Chen 	if (ret) {
226*b8fb8531SJoseph Chen 		printf("failed, ret=%d\n", ret);
227*b8fb8531SJoseph Chen 		return ret;
228*b8fb8531SJoseph Chen 	}
229*b8fb8531SJoseph Chen 	printf("OK\n");
230*b8fb8531SJoseph Chen 
231*b8fb8531SJoseph Chen 	return 0;
232*b8fb8531SJoseph Chen }
233*b8fb8531SJoseph Chen 
234bb4a1f43SJoseph Chen static int brought_up_amp(void *fit, int noffset,
235bb4a1f43SJoseph Chen 			  boot_cpu_t *bootcpu, int is_linux)
236bb4a1f43SJoseph Chen {
237bb4a1f43SJoseph Chen 	const char *desc;
238bb4a1f43SJoseph Chen 	boot_args_t args;
239bb4a1f43SJoseph Chen 	u32 cpu, aarch64, hyp;
240bb4a1f43SJoseph Chen 	u32 load, thumb, us;
241bb4a1f43SJoseph Chen 	u32 pe_state, entry;
242d184e484SJoseph Chen 	int boot_on;
243bb4a1f43SJoseph Chen 	int data_size;
244d184e484SJoseph Chen 	int i, ret;
245*b8fb8531SJoseph Chen 	u8 type = -ENODATA;
246bb4a1f43SJoseph Chen 	u8 arch = -ENODATA;
2474388decaSJoseph Chen 
24831f8f6ebSJoseph Chen 	desc = fdt_getprop(fit, noffset, "description", NULL);
24931f8f6ebSJoseph Chen 	cpu = fit_get_u32_default(fit, noffset, "cpu", -ENODATA);
25031f8f6ebSJoseph Chen 	hyp = fit_get_u32_default(fit, noffset, "hyp", 0);
25131f8f6ebSJoseph Chen 	thumb = fit_get_u32_default(fit, noffset, "thumb", 0);
252*b8fb8531SJoseph Chen 	entry = load = fit_get_u32_default(fit, noffset, "load", -ENODATA);
25331f8f6ebSJoseph Chen 	us = fit_get_u32_default(fit, noffset, "udelay", 0);
254d184e484SJoseph Chen 	boot_on = fit_get_u32_default(fit, noffset, "boot-on", 1);
25531f8f6ebSJoseph Chen 	fit_image_get_arch(fit, noffset, &arch);
256*b8fb8531SJoseph Chen 	fit_image_get_type(fit, noffset, &type);
25731f8f6ebSJoseph Chen 	fit_image_get_data_size(fit, noffset, &data_size);
258bb4a1f43SJoseph Chen 	memset(&args, 0, sizeof(args));
2594388decaSJoseph Chen 
260*b8fb8531SJoseph Chen 	/* standalone is simple, just handle it and then exit. Allow failure */
261*b8fb8531SJoseph Chen 	if (type == IH_TYPE_STANDALONE) {
262*b8fb8531SJoseph Chen 		if (!desc || load == -ENODATA) {
263*b8fb8531SJoseph Chen 			AMP_E("standalone: \"desc\" or \"load\" property missing!\n");
264*b8fb8531SJoseph Chen 			goto exit;
265*b8fb8531SJoseph Chen 		}
266*b8fb8531SJoseph Chen 		standalone_handler(desc, load, data_size);
267*b8fb8531SJoseph Chen 		goto exit;
268*b8fb8531SJoseph Chen 	}
269*b8fb8531SJoseph Chen 
270*b8fb8531SJoseph Chen 	if (!desc || cpu == -ENODATA || arch == -ENODATA || type == -ENODATA ||
271bb4a1f43SJoseph Chen 	    (load == -ENODATA && !is_linux)) {
272bb4a1f43SJoseph Chen 		AMP_E("Property missing!\n");
27331f8f6ebSJoseph Chen 		return -EINVAL;
2744388decaSJoseph Chen 	}
27531f8f6ebSJoseph Chen 	aarch64 = (arch == IH_ARCH_ARM) ? 0 : 1;
276bb4a1f43SJoseph Chen 	pe_state = PE_STATE(aarch64, hyp, thumb, 0);
27731f8f6ebSJoseph Chen 
27831f8f6ebSJoseph Chen #ifdef DEBUG
279bb4a1f43SJoseph Chen 	AMP_I("       desc: %s\n", desc);
28031f8f6ebSJoseph Chen 	AMP_I("        cpu: 0x%x\n", cpu);
28131f8f6ebSJoseph Chen 	AMP_I("    aarch64: %d\n", aarch64);
28231f8f6ebSJoseph Chen 	AMP_I("        hyp: %d\n", hyp);
28331f8f6ebSJoseph Chen 	AMP_I("      thumb: %d\n", thumb);
284*b8fb8531SJoseph Chen 	AMP_I("       load: 0x%08x\n", load);
285bb4a1f43SJoseph Chen 	AMP_I("   pe_state: 0x%08x\n", pe_state);
286bb4a1f43SJoseph Chen 	AMP_I("   linux-os: %d\n\n", is_linux);
28731f8f6ebSJoseph Chen #endif
28831f8f6ebSJoseph Chen 
289d184e484SJoseph Chen 	/* this cpu is boot cpu ? */
2906aef53bdSJoseph Chen 	if ((read_mpidr() & 0x0fff) == cpu) {
291bb4a1f43SJoseph Chen 		bootcpu->arch = arch;
292bb4a1f43SJoseph Chen 		bootcpu->entry = entry;
293bb4a1f43SJoseph Chen 		bootcpu->state = pe_state;
294bb4a1f43SJoseph Chen 		bootcpu->linux_os = is_linux;
295bb4a1f43SJoseph Chen 		return 0;
2966aef53bdSJoseph Chen 	}
2976aef53bdSJoseph Chen 
298bb4a1f43SJoseph Chen 	/* === only nonboot cpu can reach here === */
299bb4a1f43SJoseph Chen 
300bb4a1f43SJoseph Chen 	/* load or check */
301bb4a1f43SJoseph Chen 	if (is_linux) {
302bb4a1f43SJoseph Chen 		ret = load_linux_for_nonboot_cpu(cpu,
303bb4a1f43SJoseph Chen 				aarch64, load, &entry, &args);
304bb4a1f43SJoseph Chen 		if (ret)
305bb4a1f43SJoseph Chen 			return ret;
30649cfbee5SJoseph Chen 		/*
30749cfbee5SJoseph Chen 		 * Must setup before jump to linux.
30849cfbee5SJoseph Chen 		 * This is an appointment on RK amp solution to handle
30949cfbee5SJoseph Chen 		 * GIC configure competition.
31049cfbee5SJoseph Chen 		 */
31149cfbee5SJoseph Chen 		setup_sync_bits_for_linux();
312bb4a1f43SJoseph Chen 	} else {
313bb4a1f43SJoseph Chen 		if (!sysmem_alloc_base_by_name(desc,
314bb4a1f43SJoseph Chen 				(phys_addr_t)load, data_size))
31531f8f6ebSJoseph Chen 			return -ENXIO;
316f06413e4SJoseph Chen 	}
3174388decaSJoseph Chen 
318d184e484SJoseph Chen 	/* If linux assign the boot-on state, use it */
319d184e484SJoseph Chen 	for (i = 0; i < ARRAY_SIZE(g_cpus_boot_by_linux); i++) {
320d184e484SJoseph Chen 		if (cpu == g_cpus_boot_by_linux[i]) {
321d184e484SJoseph Chen 			boot_on = 0;
322d184e484SJoseph Chen 			break;
323d184e484SJoseph Chen 		}
324d184e484SJoseph Chen 	}
325d184e484SJoseph Chen 
326d184e484SJoseph Chen 	if (!boot_on)
327d184e484SJoseph Chen 		return 0;
328d184e484SJoseph Chen 
329d184e484SJoseph Chen 	/* boot now */
330257f4b84SJoseph Chen 	ret = smc_cpu_on(cpu, pe_state, entry, &args, is_linux);
331bb4a1f43SJoseph Chen 	if (ret)
33239be8a08SJoseph Chen 		return ret;
333*b8fb8531SJoseph Chen exit:
33431f8f6ebSJoseph Chen 	if (us)
33531f8f6ebSJoseph Chen 		udelay(us);
336bb4a1f43SJoseph Chen 
337bb4a1f43SJoseph Chen 	return 0;
33839be8a08SJoseph Chen }
3394388decaSJoseph Chen 
340bb4a1f43SJoseph Chen static int brought_up_all_amp(void *fit, const char *fit_uname_cfg)
341bb4a1f43SJoseph Chen {
342bb4a1f43SJoseph Chen 	int loadables_index;
343bb4a1f43SJoseph Chen 	int linux_noffset;
344bb4a1f43SJoseph Chen 	int conf_noffset;
345bb4a1f43SJoseph Chen 	int cpu_noffset;
346bb4a1f43SJoseph Chen 	int ret;
347bb4a1f43SJoseph Chen 	const char *uname;
348bb4a1f43SJoseph Chen 
349bb4a1f43SJoseph Chen 	conf_noffset = fit_conf_get_node(fit, fit_uname_cfg);
350bb4a1f43SJoseph Chen 	if (conf_noffset < 0)
351bb4a1f43SJoseph Chen 		return conf_noffset;
352bb4a1f43SJoseph Chen 
353bb4a1f43SJoseph Chen 	linux_noffset = fdt_subnode_offset(fit, conf_noffset, "linux");
354bb4a1f43SJoseph Chen 	if (linux_noffset > 0) {
355bb4a1f43SJoseph Chen 		ret = brought_up_amp(fit, linux_noffset, &g_bootcpu, 1);
356bb4a1f43SJoseph Chen 		if (ret)
357bb4a1f43SJoseph Chen 			return ret;
358bb4a1f43SJoseph Chen 	}
359bb4a1f43SJoseph Chen 
360bb4a1f43SJoseph Chen 	for (loadables_index = 0;
361bb4a1f43SJoseph Chen 	     uname = fdt_stringlist_get(fit, conf_noffset,
362bb4a1f43SJoseph Chen 			FIT_LOADABLE_PROP, loadables_index, NULL), uname;
363bb4a1f43SJoseph Chen 	     loadables_index++) {
364bb4a1f43SJoseph Chen 		cpu_noffset = fit_image_get_node(fit, uname);
365bb4a1f43SJoseph Chen 		if (cpu_noffset < 0)
366bb4a1f43SJoseph Chen 			return cpu_noffset;
367bb4a1f43SJoseph Chen 
368bb4a1f43SJoseph Chen 		ret = brought_up_amp(fit, cpu_noffset, &g_bootcpu, 0);
369bb4a1f43SJoseph Chen 		if (ret)
370bb4a1f43SJoseph Chen 			return ret;
371bb4a1f43SJoseph Chen 	}
372bb4a1f43SJoseph Chen 
373bb4a1f43SJoseph Chen 	/* === only boot cpu can reach here === */
374bb4a1f43SJoseph Chen 
375*b8fb8531SJoseph Chen 	if (!g_bootcpu.linux_os && g_bootcpu.entry) {
37631f8f6ebSJoseph Chen 		flush_dcache_all();
37731f8f6ebSJoseph Chen 		AMP_I("Brought up cpu[%x, self] with state 0x%x, entry 0x%08x ...",
378bb4a1f43SJoseph Chen 		      (u32)read_mpidr() & 0x0fff, g_bootcpu.state, g_bootcpu.entry);
37931f8f6ebSJoseph Chen 		cleanup_before_linux();
38031f8f6ebSJoseph Chen 		printf("OK\n");
381187bcfa0SJoseph Chen #ifdef CONFIG_ARM64
382bb4a1f43SJoseph Chen 		armv8_switch_to_el2(0, 0, 0, g_bootcpu.state, (u64)g_bootcpu.entry,
383bb4a1f43SJoseph Chen 		     g_bootcpu.arch == IH_ARCH_ARM ? ES_TO_AARCH32 : ES_TO_AARCH64);
384187bcfa0SJoseph Chen #else
385187bcfa0SJoseph Chen 		void (*armv7_entry)(void);
386187bcfa0SJoseph Chen 
387187bcfa0SJoseph Chen 		armv7_entry = (void (*)(void))g_bootcpu.entry;
388187bcfa0SJoseph Chen 		armv7_entry();
389187bcfa0SJoseph Chen #endif
3904388decaSJoseph Chen 	}
3914388decaSJoseph Chen 
392bb4a1f43SJoseph Chen 	/* return: boot cpu continue to boot linux */
393bb4a1f43SJoseph Chen 	return 0;
39431f8f6ebSJoseph Chen }
3954388decaSJoseph Chen 
39631f8f6ebSJoseph Chen int amp_cpus_on(void)
3974388decaSJoseph Chen {
39831f8f6ebSJoseph Chen 	struct blk_desc *dev_desc;
39931f8f6ebSJoseph Chen 	bootm_headers_t images;
40031f8f6ebSJoseph Chen 	disk_partition_t part;
401043d91f2SJoseph Chen 	void *hdr, *fit;
402043d91f2SJoseph Chen 	int offset, cnt;
403043d91f2SJoseph Chen 	int totalsize;
40431f8f6ebSJoseph Chen 	int ret = 0;
40531f8f6ebSJoseph Chen 
40631f8f6ebSJoseph Chen 	dev_desc = rockchip_get_bootdev();
40731f8f6ebSJoseph Chen 	if (!dev_desc)
40831f8f6ebSJoseph Chen 		return -EIO;
40931f8f6ebSJoseph Chen 
41031f8f6ebSJoseph Chen 	if (part_get_info_by_name(dev_desc, AMP_PART, &part) < 0)
41131f8f6ebSJoseph Chen 		return -ENODEV;
41231f8f6ebSJoseph Chen 
413043d91f2SJoseph Chen 	hdr = memalign(ARCH_DMA_MINALIGN, FIT_HEADER_SIZE);
414043d91f2SJoseph Chen 	if (!hdr)
41531f8f6ebSJoseph Chen 		return -ENOMEM;
41631f8f6ebSJoseph Chen 
417043d91f2SJoseph Chen 	/* get totalsize */
418043d91f2SJoseph Chen 	offset = part.start;
419043d91f2SJoseph Chen 	cnt = DIV_ROUND_UP(FIT_HEADER_SIZE, part.blksz);
420043d91f2SJoseph Chen 	if (blk_dread(dev_desc, offset, cnt, hdr) != cnt) {
42131f8f6ebSJoseph Chen 		ret = -EIO;
422043d91f2SJoseph Chen 		goto out2;
4234388decaSJoseph Chen 	}
4244388decaSJoseph Chen 
425043d91f2SJoseph Chen 	if (fdt_check_header(hdr)) {
426bb4a1f43SJoseph Chen 		AMP_E("Not fit\n");
42731f8f6ebSJoseph Chen 		ret = -EINVAL;
428043d91f2SJoseph Chen 		goto out2;
429043d91f2SJoseph Chen 	}
430043d91f2SJoseph Chen 
431043d91f2SJoseph Chen 	if (fit_get_totalsize(hdr, &totalsize)) {
432043d91f2SJoseph Chen 		AMP_E("No totalsize\n");
433043d91f2SJoseph Chen 		ret = -EINVAL;
434043d91f2SJoseph Chen 		goto out2;
435043d91f2SJoseph Chen 	}
436043d91f2SJoseph Chen 
437043d91f2SJoseph Chen 	/* load image */
438043d91f2SJoseph Chen 	fit = memalign(ARCH_DMA_MINALIGN, ALIGN(totalsize, part.blksz));
439043d91f2SJoseph Chen 	if (!fit) {
440043d91f2SJoseph Chen 		printf("No memory\n");
441043d91f2SJoseph Chen 		ret = -ENOMEM;
442043d91f2SJoseph Chen 		goto out2;
443043d91f2SJoseph Chen 	}
444043d91f2SJoseph Chen 
445043d91f2SJoseph Chen 	memcpy(fit, hdr, FIT_HEADER_SIZE);
446043d91f2SJoseph Chen 
447043d91f2SJoseph Chen 	offset += cnt;
448043d91f2SJoseph Chen 	cnt = DIV_ROUND_UP(totalsize, part.blksz) - cnt;
449043d91f2SJoseph Chen 	if (blk_dread(dev_desc, offset, cnt, fit + FIT_HEADER_SIZE) != cnt) {
450043d91f2SJoseph Chen 		ret = -EIO;
451043d91f2SJoseph Chen 		goto out1;
45231f8f6ebSJoseph Chen 	}
4534388decaSJoseph Chen 
454d184e484SJoseph Chen 	/* prase linux info */
455d184e484SJoseph Chen 	parse_cpus_boot_by_linux();
456d184e484SJoseph Chen 
457bb4a1f43SJoseph Chen 	/* Load loadables */
45831f8f6ebSJoseph Chen 	memset(&images, 0, sizeof(images));
45931f8f6ebSJoseph Chen 	images.fit_uname_cfg = "conf";
46031f8f6ebSJoseph Chen 	images.fit_hdr_os = fit;
46131f8f6ebSJoseph Chen 	images.verify = 1;
462bb4a1f43SJoseph Chen 	ret = boot_get_loadable(0, NULL, &images, IH_ARCH_DEFAULT, NULL, NULL);
46331f8f6ebSJoseph Chen 	if (ret) {
464bb4a1f43SJoseph Chen 		AMP_E("Load loadables, ret=%d\n", ret);
465043d91f2SJoseph Chen 		goto out1;
46631f8f6ebSJoseph Chen 	}
46731f8f6ebSJoseph Chen 	flush_dcache_all();
46831f8f6ebSJoseph Chen 
469bb4a1f43SJoseph Chen 	/* Wakeup */
47031f8f6ebSJoseph Chen 	ret = brought_up_all_amp(images.fit_hdr_os, images.fit_uname_cfg);
471bb4a1f43SJoseph Chen 	if (ret)
472bb4a1f43SJoseph Chen 		AMP_E("Brought up amps, ret=%d\n", ret);
473043d91f2SJoseph Chen out1:
474bb4a1f43SJoseph Chen 	free(fit);
475043d91f2SJoseph Chen out2:
476043d91f2SJoseph Chen 	free(hdr);
47731f8f6ebSJoseph Chen 
47831f8f6ebSJoseph Chen 	return ret;
47931f8f6ebSJoseph Chen }
48031f8f6ebSJoseph Chen 
4818223aa47SJoseph Chen int arm64_switch_amp_pe(bootm_headers_t *images)
48231f8f6ebSJoseph Chen {
483bb4a1f43SJoseph Chen 	images->os.arch = g_bootcpu.arch;
484bb4a1f43SJoseph Chen 	return g_bootcpu.state;
48531f8f6ebSJoseph Chen }
48631f8f6ebSJoseph Chen 
487